Skip to content

Commit

Permalink
support for applicationCredentialName
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinWeindel committed Jul 1, 2021
1 parent 9adf589 commit 4a52a3a
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
auth-url="{{ .Values.authUrl }}"
domain-name="{{ .Values.domainName }}"
tenant-name="{{ .Values.tenantName }}"
{{- if .Values.username }}
username="{{ .Values.username }}"
{{- if .Values.password }}
password="{{ .Values.password }}"
{{- end }}
{{- if .Values.applicationCredentialID }}
{{- if .Values.applicationCredentialSecret }}
application-credential-id="{{ .Values.applicationCredentialID }}"
application-credential-name="{{ .Values.applicationCredentialName }}"
application-credential-secret="{{ .Values.applicationCredentialSecret }}"
{{- end }}
region="{{ .Values.region }}"
Expand Down
3 changes: 3 additions & 0 deletions charts/internal/cloud-provider-config/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ domainName: fooDomain
tenantName: fooTenant
username: barUser
password: barPass
# applicationCredentialID: barID
# applicationCredentialName: barName
# applicationCredentialSecret: barSecret
region: eu
# [LoadBalancer]
lbProvider: foobar
Expand Down
1 change: 1 addition & 0 deletions docs/usage-as-end-user.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ data:

# or application credentials
#applicationCredentialID: base64(app-credential-id)
#applicationCredentialName: base64(app-credential-name) # optional
#applicationCredentialSecret: base64(app-credential-secret)
```

Expand Down
1 change: 1 addition & 0 deletions pkg/apis/openstack/validation/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func ValidateCloudProviderSecret(secret *corev1.Secret) error {
openstack.TenantName: credentials.TenantName,
openstack.UserName: credentials.Username,
openstack.ApplicationCredentialID: credentials.ApplicationCredentialID,
openstack.ApplicationCredentialName: credentials.ApplicationCredentialName,
openstack.ApplicationCredentialSecret: credentials.ApplicationCredentialSecret,
} {
if strings.TrimSpace(value) != value {
Expand Down
58 changes: 52 additions & 6 deletions pkg/apis/openstack/validation/secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,18 @@ var _ = Describe("Secret validation", func() {
HaveOccurred(),
),

Entry("should return error when the application credential name contains a trailing new line",
map[string][]byte{
openstack.DomainName: []byte("domain"),
openstack.TenantName: []byte("tenant"),
openstack.UserName: []byte("user"),
openstack.ApplicationCredentialID: []byte("app-id"),
openstack.ApplicationCredentialName: []byte("app-name\n"),
openstack.ApplicationCredentialSecret: []byte("app-secret"),
},
HaveOccurred(),
),

Entry("should return error when neither username nor application credential id is given",
map[string][]byte{
openstack.DomainName: []byte("domain"),
Expand All @@ -225,12 +237,12 @@ var _ = Describe("Secret validation", func() {
HaveOccurred(),
),

Entry("should return error when both username and application credential id is given",
Entry("should return error when both password and application credential secret is given",
map[string][]byte{
openstack.DomainName: []byte("domain"),
openstack.TenantName: []byte("tenant"),
openstack.UserName: []byte("user"),
openstack.ApplicationCredentialID: []byte("app-id"),
openstack.DomainName: []byte("domain"),
openstack.TenantName: []byte("tenant"),
openstack.Password: []byte("password"),
openstack.ApplicationCredentialSecret: []byte("app-secret"),
},
HaveOccurred(),
),
Expand All @@ -244,7 +256,17 @@ var _ = Describe("Secret validation", func() {
HaveOccurred(),
),

Entry("should succeed when the client application credentials are valid (with AuthURL)",
Entry("should return error when application credential name is given, but without user name",
map[string][]byte{
openstack.DomainName: []byte("domain"),
openstack.TenantName: []byte("tenant"),
openstack.ApplicationCredentialName: []byte("app-name"),
openstack.ApplicationCredentialSecret: []byte("app-secret"),
},
HaveOccurred(),
),

Entry("should succeed when the client application credentials are valid (id + secret)",
map[string][]byte{
openstack.DomainName: []byte("domain"),
openstack.TenantName: []byte("tenant"),
Expand All @@ -254,5 +276,29 @@ var _ = Describe("Secret validation", func() {
},
BeNil(),
),

Entry("should succeed when the client application credentials are valid (id + name + secret)",
map[string][]byte{
openstack.DomainName: []byte("domain"),
openstack.TenantName: []byte("tenant"),
openstack.ApplicationCredentialID: []byte("app-id"),
openstack.ApplicationCredentialName: []byte("app-name"),
openstack.ApplicationCredentialSecret: []byte("app-secret"),
openstack.AuthURL: []byte("https://foo.bar"),
},
BeNil(),
),

Entry("should succeed when the client application credentials are valid (username + name + secret)",
map[string][]byte{
openstack.DomainName: []byte("domain"),
openstack.TenantName: []byte("tenant"),
openstack.UserName: []byte("user"),
openstack.ApplicationCredentialName: []byte("app-name"),
openstack.ApplicationCredentialSecret: []byte("app-secret"),
openstack.AuthURL: []byte("https://foo.bar"),
},
BeNil(),
),
)
})
1 change: 1 addition & 0 deletions pkg/controller/controlplane/valuesprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ func getConfigChartValues(
"username": c.Username,
"password": c.Password,
"applicationCredentialID": c.ApplicationCredentialID,
"applicationCredentialName": c.ApplicationCredentialName,
"applicationCredentialSecret": c.ApplicationCredentialSecret,
"region": cp.Spec.Region,
"lbProvider": cpConfig.LoadBalancerProvider,
Expand Down
3 changes: 1 addition & 2 deletions pkg/controller/infrastructure/actuator_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ func (a *actuator) Delete(ctx context.Context, infra *extensionsv1alpha1.Infrast
if err != nil {
return err
}
useApplicationCredentials := credentials.ApplicationCredentialID != ""

return tf.
SetEnvVars(internal.TerraformerEnvVars(infra.Spec.SecretRef, useApplicationCredentials)...).
SetEnvVars(internal.TerraformerEnvVars(infra.Spec.SecretRef, credentials)...).
Destroy(ctx)
}
3 changes: 1 addition & 2 deletions pkg/controller/infrastructure/actuator_reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ func (a *actuator) reconcile(ctx context.Context, logger logr.Logger, infra *ext
if err != nil {
return err
}
useApplicationCredentials := credentials.ApplicationCredentialID != ""

tf, err := internal.NewTerraformerWithAuth(logger, a.RESTConfig(), infrastructure.TerraformerPurpose, infra, useApplicationCredentials)
tf, err := internal.NewTerraformerWithAuth(logger, a.RESTConfig(), infrastructure.TerraformerPurpose, infra, credentials)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/internal/infrastructure/templates/main.tpl.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ provider "openstack" {
user_name = var.USER_NAME
password = var.PASSWORD
application_credential_id = var.APPLICATION_CREDENTIAL_ID
application_credential_name = var.APPLICATION_CREDENTIAL_NAME
application_credential_secret = var.APPLICATION_CREDENTIAL_SECRET
insecure = true
max_retries = "{{ .openstack.maxApiCallRetries }}"
Expand Down
8 changes: 7 additions & 1 deletion pkg/internal/infrastructure/templates/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ variable "TENANT_NAME" {
variable "USER_NAME" {
description = "OpenStack user name"
type = string
default = "" # not needed if application credentials are used
default = "" # not needed if application credentials are used with APPLICATION_CREDENTIAL_ID
}

variable "PASSWORD" {
Expand All @@ -26,6 +26,12 @@ variable "APPLICATION_CREDENTIAL_ID" {
default = "" # not needed if username/password are used
}

variable "APPLICATION_CREDENTIAL_NAME" {
description = "OpenStack application credential name"
type = string
default = "" # not needed if username/password are used or APPLICATION_CREDENTIAL_ID is given
}

variable "APPLICATION_CREDENTIAL_SECRET" {
description = "OpenStack application credential secret"
type = string
Expand Down
43 changes: 29 additions & 14 deletions pkg/internal/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,44 @@ const (
TerraformVarNamePassword = "TF_VAR_PASSWORD"
// TerraformVarNameApplicationCredentialId maps to terraform internal var representation.
TerraformVarNameApplicationCredentialId = "TF_VAR_APPLICATION_CREDENTIAL_ID"
// TerraformVarNameApplicationCredentialName maps to terraform internal var representation.
TerraformVarNameApplicationCredentialName = "TF_VAR_APPLICATION_CREDENTIAL_NAME"
// TerraformVarNameApplicationCredentialSecret maps to terraform internal var representation.
TerraformVarNameApplicationCredentialSecret = "TF_VAR_APPLICATION_CREDENTIAL_SECRET"
)

const (
TerraformAuthUsernamePassword = 0
TerraformAuthApplicationCredentialID
TerraformAuthApplicationCredentialName
)

// TerraformerEnvVars computes the Terraformer environment variables from the given secret reference.
func TerraformerEnvVars(secretRef corev1.SecretReference, useApplicationCredentials bool) []corev1.EnvVar {
name1 := TerraformVarNameUserName
key1 := openstack.UserName
name2 := TerraformVarNamePassword
key2 := openstack.Password
func TerraformerEnvVars(secretRef corev1.SecretReference, credentials *openstack.Credentials) []corev1.EnvVar {

if useApplicationCredentials {
name1 = TerraformVarNameApplicationCredentialId
key1 = openstack.ApplicationCredentialID
name2 = TerraformVarNameApplicationCredentialSecret
key2 = openstack.ApplicationCredentialSecret
if credentials.ApplicationCredentialSecret != "" {
envVars := []corev1.EnvVar{
createEnvVar(secretRef, TerraformVarNameDomainName, openstack.DomainName),
createEnvVar(secretRef, TerraformVarNameProjectName, openstack.TenantName),
createEnvVar(secretRef, TerraformVarNameApplicationCredentialSecret, openstack.ApplicationCredentialSecret),
}
if credentials.ApplicationCredentialID != "" {
envVars = append(envVars, createEnvVar(secretRef, TerraformVarNameApplicationCredentialId, openstack.ApplicationCredentialID))
}
if credentials.ApplicationCredentialName != "" {
envVars = append(envVars, createEnvVar(secretRef, TerraformVarNameApplicationCredentialName, openstack.ApplicationCredentialName))
}
if credentials.Username != "" {
envVars = append(envVars, createEnvVar(secretRef, TerraformVarNameUserName, openstack.UserName))
}
return envVars
}

return []corev1.EnvVar{
createEnvVar(secretRef, TerraformVarNameDomainName, openstack.DomainName),
createEnvVar(secretRef, TerraformVarNameProjectName, openstack.TenantName),
createEnvVar(secretRef, name1, key1),
createEnvVar(secretRef, name2, key2),
createEnvVar(secretRef, TerraformVarNameUserName, openstack.UserName),
createEnvVar(secretRef, TerraformVarNamePassword, openstack.Password),
}
}

Expand Down Expand Up @@ -92,14 +107,14 @@ func NewTerraformerWithAuth(
restConfig *rest.Config,
purpose string,
infra *extensionsv1alpha1.Infrastructure,
useApplicationCredentials bool,
credentials *openstack.Credentials,
) (terraformer.Terraformer, error) {
tf, err := NewTerraformer(logger, restConfig, purpose, infra)
if err != nil {
return nil, err
}

return tf.SetEnvVars(TerraformerEnvVars(infra.Spec.SecretRef, useApplicationCredentials)...), nil
return tf.SetEnvVars(TerraformerEnvVars(infra.Spec.SecretRef, credentials)...), nil
}

func createEnvVar(secretRef corev1.SecretReference, name, key string) corev1.EnvVar {
Expand Down
66 changes: 63 additions & 3 deletions pkg/internal/terraform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package internal

import (
"github.com/gardener/gardener-extension-provider-openstack/pkg/openstack"
corev1 "k8s.io/api/core/v1"

. "github.com/onsi/ginkgo"
Expand All @@ -25,7 +26,8 @@ var _ = Describe("Terraform", func() {
Describe("#TerraformerEnvVars", func() {
It("should correctly create the environment variables for username/password", func() {
secretRef := corev1.SecretReference{Name: "cloud"}
Expect(TerraformerEnvVars(secretRef, false)).To(ConsistOf(
credentials := &openstack.Credentials{}
Expect(TerraformerEnvVars(secretRef, credentials)).To(ConsistOf(
corev1.EnvVar{
Name: "TF_VAR_DOMAIN_NAME",
ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{
Expand Down Expand Up @@ -63,9 +65,13 @@ var _ = Describe("Terraform", func() {
}},
}))
})
It("should correctly create the environment variables for application credentials", func() {
It("should correctly create the environment variables for application credentials (id + secret)", func() {
secretRef := corev1.SecretReference{Name: "cloud"}
Expect(TerraformerEnvVars(secretRef, true)).To(ConsistOf(
credentials := &openstack.Credentials{
ApplicationCredentialSecret: "secret",
ApplicationCredentialID: "appid",
}
Expect(TerraformerEnvVars(secretRef, credentials)).To(ConsistOf(
corev1.EnvVar{
Name: "TF_VAR_DOMAIN_NAME",
ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{
Expand Down Expand Up @@ -103,5 +109,59 @@ var _ = Describe("Terraform", func() {
}},
}))
})
It("should correctly create the environment variables for application credentials (username + name + secret)", func() {
secretRef := corev1.SecretReference{Name: "cloud"}
credentials := &openstack.Credentials{
Username: "fred",
ApplicationCredentialName: "appname",
ApplicationCredentialSecret: "secret",
}
Expect(TerraformerEnvVars(secretRef, credentials)).To(ConsistOf(
corev1.EnvVar{
Name: "TF_VAR_DOMAIN_NAME",
ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretRef.Name,
},
Key: "domainName",
}},
},
corev1.EnvVar{
Name: "TF_VAR_TENANT_NAME",
ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretRef.Name,
},
Key: "tenantName",
}},
},
corev1.EnvVar{
Name: "TF_VAR_APPLICATION_CREDENTIAL_NAME",
ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretRef.Name,
},
Key: "applicationCredentialName",
}},
},
corev1.EnvVar{
Name: "TF_VAR_APPLICATION_CREDENTIAL_SECRET",
ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretRef.Name,
},
Key: "applicationCredentialSecret",
}},
},
corev1.EnvVar{
Name: "TF_VAR_USER_NAME",
ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretRef.Name,
},
Key: "username",
}},
}))
})
})
})
3 changes: 2 additions & 1 deletion pkg/openstack/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ func NewOpenstackClientFromCredentials(credentials *os.Credentials) (Factory, er
ProjectName: credentials.TenantName,
DomainName: credentials.DomainName,
ApplicationCredentialID: credentials.ApplicationCredentialID,
ApplicationCredentialName: credentials.ApplicationCredentialName,
ApplicationCredentialSecret: credentials.ApplicationCredentialSecret,
},
}

if opts.AuthInfo.ApplicationCredentialID != "" {
if opts.AuthInfo.ApplicationCredentialSecret != "" {
opts.AuthType = clientconfig.AuthV3ApplicationCredential
}

Expand Down
Loading

0 comments on commit 4a52a3a

Please sign in to comment.