From 1ceee41890e91124f27e1022f1dadfe029083677 Mon Sep 17 00:00:00 2001 From: Russel Vela Date: Fri, 23 Oct 2020 17:58:05 -0500 Subject: [PATCH] Added Zone field to the Role path. This field takes priority over the Zone field in the Venafi Secret path. If set, it will be used for making the Connection to the Venafi platform. Updated the test suite to accommodate for these changes. --- plugin/pki/backend_test.go | 11 ++++ plugin/pki/env_test.go | 83 ++++++++++++++++++++++++++- plugin/pki/path_roles.go | 93 ++++++++++++++++++------------- plugin/pki/path_venafi_secrets.go | 29 ++++------ plugin/pki/util.go | 14 +++++ plugin/pki/vcert.go | 13 ++++- 6 files changed, 181 insertions(+), 62 deletions(-) diff --git a/plugin/pki/backend_test.go b/plugin/pki/backend_test.go index 4bcbd7e5..79164171 100644 --- a/plugin/pki/backend_test.go +++ b/plugin/pki/backend_test.go @@ -170,3 +170,14 @@ func TestTokenIntegration(t *testing.T) { t.Run("TPP Token sign certificate and ttl attribute", integrationTestEnv.TokenIntegrationSignWithTTLCertificate) } + +func TestZoneOverride(t *testing.T) { + + integrationTestEnv, err := newIntegrationTestEnv() + if err != nil { + t.Fatal(err) + } + + t.Run("Token enroll with role zone", integrationTestEnv.TokenEnrollWithRoleZone) + t.Run("Token enroll with Venafi secret zone", integrationTestEnv.TokenEnrollWithVenafiSecretZone) +} diff --git a/plugin/pki/env_test.go b/plugin/pki/env_test.go index bf320d48..4a5fb31d 100644 --- a/plugin/pki/env_test.go +++ b/plugin/pki/env_test.go @@ -71,9 +71,10 @@ const ( venafiConfigMixedTppAndCloud venafiConfigString = "MixedTppCloud" venafiConfigMixedTppAndToken venafiConfigString = "MixedTppToken" venafiConfigMixedTokenAndCloud venafiConfigString = "MixedTokenCloud" - - venafiVenafiConfigFake venafiConfigString = "VenafiFake" - venafiRoleConfig venafiConfigString = "Role" + venafiVenafiConfigFake venafiConfigString = "VenafiFake" + venafiRoleConfig venafiConfigString = "Role" + venafiRoleWithZoneConfig venafiConfigString = "venafiRoleWithZone" + venafiRoleWithVenafiSecretConfig venafiConfigString = "venafiVenafiSecretZone" ) var venafiTestRoleConfig = map[string]interface{}{ @@ -128,6 +129,12 @@ var venafiTestTokenConfig = map[string]interface{}{ "trust_bundle_file": os.Getenv("TRUST_BUNDLE"), } +var venafiTestTokenConfigForRoleZone = map[string]interface{}{ + "zone": os.Getenv("TPP_ZONE2"), +} + +var venafiTestTokenConfigForVenafiSecretZone = map[string]interface{}{} + var venafiTestTokenConfigPredefined = map[string]interface{}{ "url": "https://tpp.example.com", "access_token": "admin", @@ -212,6 +219,39 @@ func (e *testEnv) writeRoleToBackend(t *testing.T, configString venafiConfigStri if err != nil { t.Fatal(err) } + roleData = copyMap(roleData) + + //Adding Venafi secret reference to Role + roleData["venafi_secret"] = e.VenafiSecretName + //Removing the zone from the data, as the Venafi secret zone must be used + roleData["zone"] = "" + + ttl := strconv.Itoa(role_ttl_test_property) + "h" + roleData["ttl"] = ttl + roleData["issuer_hint"] = util.IssuerHintMicrosoft + + resp, err := e.Backend.HandleRequest(e.Context, &logical.Request{ + Operation: logical.UpdateOperation, + Path: "roles/" + e.RoleName, + Storage: e.Storage, + Data: roleData, + }) + + if err != nil { + t.Fatal(err) + } + + if resp != nil && resp.IsError() { + t.Fatalf("failed to create role, %#v", resp) + } +} + +func (e *testEnv) writeRoleWithZoneToBackend(t *testing.T, configString venafiConfigString) { + roleData, err := makeConfig(configString) + if err != nil { + t.Fatal(err) + } + roleData = copyMap(roleData) //Adding Venafi secret reference to Role roleData["venafi_secret"] = e.VenafiSecretName @@ -342,6 +382,7 @@ func (e *testEnv) writeVenafiToBackend(t *testing.T, configString venafiConfigSt if err != nil { t.Fatal(err) } + roleData = copyMap(roleData) resp, err := e.Backend.HandleRequest(e.Context, &logical.Request{ Operation: logical.UpdateOperation, @@ -956,6 +997,10 @@ func makeConfig(configString venafiConfigString) (roleData map[string]interface{ roleData = venafiVenafiTestFakeConfig case venafiRoleConfig: roleData = venafiTestRoleConfig + case venafiRoleWithZoneConfig: + roleData = venafiTestTokenConfigForRoleZone + case venafiRoleWithVenafiSecretConfig: + roleData = venafiTestTokenConfigForVenafiSecretZone default: return roleData, fmt.Errorf("do not have config data for config %s", configString) } @@ -1642,6 +1687,38 @@ func (e *testEnv) TokenIntegrationIssueCertificateWithTTLOnIssueData(t *testing. e.IssueCertificateAndValidateTTL(t, data) } +func (e *testEnv) TokenEnrollWithRoleZone(t *testing.T) { + data := testData{} + randString := e.TestRandString + domain := "venafi.example.com" + data.cn = randString + "." + domain + data.dnsNS = "alt-" + data.cn + data.dnsIP = "192.168.1.1" + data.dnsEmail = "venafi@example.com" + + var config = venafiConfigToken + var roleConfig = venafiRoleWithZoneConfig + e.writeVenafiToBackend(t, config) + e.writeRoleWithZoneToBackend(t, roleConfig) + e.IssueCertificateAndSaveSerial(t, data, config) +} + +func (e *testEnv) TokenEnrollWithVenafiSecretZone(t *testing.T) { + data := testData{} + randString := e.TestRandString + domain := "venafi.example.com" + data.cn = randString + "." + domain + data.dnsNS = "alt-" + data.cn + data.dnsIP = "192.168.1.1" + data.dnsEmail = "venafi@example.com" + + var config = venafiConfigToken + var roleConfig = venafiRoleWithVenafiSecretConfig + e.writeVenafiToBackend(t, config) + e.writeRoleWithZoneToBackend(t, roleConfig) + e.IssueCertificateAndSaveSerial(t, data, config) +} + func checkStandardCert(t *testing.T, data testData) { var err error log.Println("Testing certificate:", data.cert) diff --git a/plugin/pki/path_roles.go b/plugin/pki/path_roles.go index a07bd31e..50932427 100644 --- a/plugin/pki/path_roles.go +++ b/plugin/pki/path_roles.go @@ -31,6 +31,14 @@ func pathRoles(b *backend) *framework.Path { Description: "Name of the role", Required: true, }, + "zone": { + Type: framework.TypeString, + Description: `Name of Venafi Platform policy or Venafi Cloud project zone. +This field overrides the zone field declared in the Venafi secret. +Example for Platform: testpolicy\\vault +Example for Venafi Cloud: e33f3e40-4e7e-11ea-8da3-b3c196ebeb0b`, + Required: false, + }, "store_by_cn": { Type: framework.TypeBool, Description: `Set it to true to store certificates by CN in certs/ path`, @@ -86,7 +94,7 @@ the key_type. Default: 2048`, Description: `Key curve for EC key type. Valid values are: "P256","P384","P521"`, }, "ttl": { - Type: framework.TypeDurationSecond, + Type: framework.TypeDurationSecond, Description: `The certificate validity if no specific certificate validity is requested.`, }, "issuer_hint": { @@ -219,69 +227,69 @@ func (b *backend) pathRoleUpdate(ctx context.Context, req *logical.Request, data } _, isSet := data.GetOk("chain_option") - chain_option := data.Get("chain_option").(string) - if isSet && (entry.ChainOption != chain_option) { - entry.ChainOption = chain_option + chainOption := data.Get("chain_option").(string) + if isSet && (entry.ChainOption != chainOption) { + entry.ChainOption = chainOption } _, isSet = data.GetOk("store_by_cn") - store_by_cn := data.Get("store_by_cn").(bool) - if isSet && store_by_cn { + storeByCn := data.Get("store_by_cn").(bool) + if isSet && storeByCn { entry.StoreBy = "cn" } _, isSet = data.GetOk("store_by_serial") - store_by_serial := data.Get("store_by_serial").(bool) - if isSet && store_by_serial { + storeBySerial := data.Get("store_by_serial").(bool) + if isSet && storeBySerial { entry.StoreBy = "serial" } _, isSet = data.GetOk("store_by") - store_by := data.Get("store_by").(string) - if isSet && (entry.StoreBy != store_by) { - entry.StoreBy = store_by + storeBy := data.Get("store_by").(string) + if isSet && (entry.StoreBy != storeBy) { + entry.StoreBy = storeBy } _, isSet = data.GetOk("no_store") - no_store := data.Get("no_store").(bool) - if isSet && (entry.NoStore != no_store) { - entry.NoStore = no_store + noStore := data.Get("no_store").(bool) + if isSet && (entry.NoStore != noStore) { + entry.NoStore = noStore } _, isSet = data.GetOk("service_generated_cert") - service_generated_cert := data.Get("service_generated_cert").(bool) - if isSet && (entry.ServiceGenerated != service_generated_cert) { - entry.ServiceGenerated = service_generated_cert + serviceGeneratedCert := data.Get("service_generated_cert").(bool) + if isSet && (entry.ServiceGenerated != serviceGeneratedCert) { + entry.ServiceGenerated = serviceGeneratedCert } _, isSet = data.GetOk("store_pkey") - store_pkey := data.Get("store_pkey").(bool) - if isSet && (entry.StorePrivateKey != store_pkey) { - entry.StorePrivateKey = store_pkey + storePkey := data.Get("store_pkey").(bool) + if isSet && (entry.StorePrivateKey != storePkey) { + entry.StorePrivateKey = storePkey } _, isSet = data.GetOk("key_type") - key_type := data.Get("key_type").(string) - if isSet && (entry.KeyType != key_type) { - entry.KeyType = key_type + keyType := data.Get("key_type").(string) + if isSet && (entry.KeyType != keyType) { + entry.KeyType = keyType } _, isSet = data.GetOk("key_bits") - key_bits := data.Get("key_bits").(int) - if isSet && (entry.KeyBits != key_bits) { - entry.KeyBits = key_bits + keyBits := data.Get("key_bits").(int) + if isSet && (entry.KeyBits != keyBits) { + entry.KeyBits = keyBits } _, isSet = data.GetOk("key_curve") - key_curve := data.Get("key_curve").(string) - if isSet && (entry.KeyCurve != key_curve) { - entry.KeyCurve = key_curve + keyCurve := data.Get("key_curve").(string) + if isSet && (entry.KeyCurve != keyCurve) { + entry.KeyCurve = keyCurve } _, isSet = data.GetOk("max_ttl") - max_ttl := time.Duration(data.Get("max_ttl").(int)) * time.Second - if isSet && (entry.MaxTTL != max_ttl) { - entry.MaxTTL = max_ttl + maxTtl := time.Duration(data.Get("max_ttl").(int)) * time.Second + if isSet && (entry.MaxTTL != maxTtl) { + entry.MaxTTL = maxTtl } _, isSet = data.GetOk("ttl") @@ -291,15 +299,15 @@ func (b *backend) pathRoleUpdate(ctx context.Context, req *logical.Request, data } _, isSet = data.GetOk("generate_lease") - generate_lease := data.Get("generate_lease").(bool) - if isSet && (entry.GenerateLease != generate_lease) { - entry.GenerateLease = generate_lease + generateLease := data.Get("generate_lease").(bool) + if isSet && (entry.GenerateLease != generateLease) { + entry.GenerateLease = generateLease } _, isSet = data.GetOk("server_timeout") - server_timeout := time.Duration(data.Get("server_timeout").(int)) * time.Second - if isSet && (entry.ServerTimeout != server_timeout) { - entry.ServerTimeout = server_timeout + serverTimeout := time.Duration(data.Get("server_timeout").(int)) * time.Second + if isSet && (entry.ServerTimeout != serverTimeout) { + entry.ServerTimeout = serverTimeout } _, isSet = data.GetOk("venafi_secret") @@ -308,6 +316,12 @@ func (b *backend) pathRoleUpdate(ctx context.Context, req *logical.Request, data entry.VenafiSecret = venafiSecret } + _, isSet = data.GetOk("zone") + zone := data.Get("zone").(string) + if isSet && (entry.Zone != zone) { + entry.Zone = zone + } + err = validateEntry(entry) if err != nil { return nil, err @@ -348,6 +362,7 @@ func (b *backend) pathRoleCreate(ctx context.Context, req *logical.Request, data GenerateLease: data.Get("generate_lease").(bool), ServerTimeout: time.Duration(data.Get("server_timeout").(int)) * time.Second, VenafiSecret: data.Get("venafi_secret").(string), + Zone: data.Get("zone").(string), } } @@ -464,11 +479,13 @@ type roleEntry struct { DeprecatedTTL string `json:"ttl"` ServerTimeout time.Duration `json:"server_timeout"` VenafiSecret string `json:"venafi_secret"` + Zone string `json:"zone"` } func (r *roleEntry) ToResponseData() map[string]interface{} { responseData := map[string]interface{}{ "venafi_secret": r.VenafiSecret, + "role_zone": r.Zone, "store_by": r.StoreBy, "no_store": r.NoStore, "service_generated_cert": r.ServiceGenerated, diff --git a/plugin/pki/path_venafi_secrets.go b/plugin/pki/path_venafi_secrets.go index 84fd32e8..ac7160b3 100644 --- a/plugin/pki/path_venafi_secrets.go +++ b/plugin/pki/path_venafi_secrets.go @@ -310,38 +310,29 @@ type venafiSecretEntry struct { } func (p *venafiSecretEntry) ToResponseData() map[string]interface{} { - var tppPass, accessToken, refreshToken, apiKey string - if p.TppPassword != "" { - tppPass = "********" - } - if p.AccessToken != "" { - accessToken = "********" - } - if p.RefreshToken != "" { - refreshToken = "********" - } - if p.Apikey != "" { - apiKey = "********" - } - responseData := map[string]interface{}{ - //Sensible data will not be returned. + //Sensible data will not be disclosed. //tpp_password, api_key, access_token, refresh_token "url": p.URL, "zone": p.Zone, "tpp_user": p.TppUser, - "tpp_password": tppPass, - "access_token": accessToken, - "refresh_token": refreshToken, - "apikey": apiKey, + "tpp_password": p.getStringMask(), + "access_token": p.getStringMask(), + "refresh_token": p.getStringMask(), + "apikey": p.getStringMask(), "trust_bundle_file": p.TrustBundleFile, "fakemode": p.Fakemode, } return responseData } +func (p *venafiSecretEntry) getStringMask() string { + return stringMask +} + const ( + stringMask = "********" pathListVenafiSecretsHelpSyn = `List the existing Venafi Secrets in this backend` // #nosec pathListVenafiSecretsHelpDesc = `Venafi Secrets will be listed by the secret name.` // #nosec pathVenafiSecretsHelpSyn = `Manage the Venafi Secrets that can be created with this backend.` // #nosec diff --git a/plugin/pki/util.go b/plugin/pki/util.go index 3a3bde02..8469f2fe 100644 --- a/plugin/pki/util.go +++ b/plugin/pki/util.go @@ -323,3 +323,17 @@ func parseTrustBundlePEM(trustBundlePem string) (*x509.CertPool, error) { return connectionTrustBundle, nil } + +func copyMap(m map[string]interface{}) map[string]interface{} { + cp := make(map[string]interface{}) + for k, v := range m { + vm, ok := v.(map[string]interface{}) + if ok { + cp[k] = copyMap(vm) + } else { + cp[k] = v + } + } + + return cp +} diff --git a/plugin/pki/vcert.go b/plugin/pki/vcert.go index fb453f10..5f2670df 100644 --- a/plugin/pki/vcert.go +++ b/plugin/pki/vcert.go @@ -73,9 +73,19 @@ func (b *backend) getConfig(ctx context.Context, req *logical.Request, roleName trustBundlePEM = string(trustBundle) } + //If the role has a Zone declared, it takes priority over the Zone in the Venafi secret + var zone string + if role.Zone != "" { + b.Logger().Debug(fmt.Sprintf("Using role zone: [%s]. Overrides venafi Secret zone: [%s]", role.Zone, venafiSecret.Zone)) + zone = role.Zone + } else { + b.Logger().Debug(fmt.Sprintf("Using venafi secret zone: [%s]. Role zone not found. ", venafiSecret.Zone)) + zone = venafiSecret.Zone + } + cfg = &vcert.Config{} cfg.BaseUrl = venafiSecret.URL - cfg.Zone = venafiSecret.Zone + cfg.Zone = zone cfg.LogVerbose = true if trustBundlePEM != "" { cfg.ConnectionTrust = trustBundlePEM @@ -124,5 +134,4 @@ func (b *backend) getConfig(ctx context.Context, req *logical.Request, roleName } return cfg, nil - }