Browse Source

#150 Implement LDAP and JWT/OIDC auth methods

xxxbobrxxx 4 years ago
parent
commit
e4d8fb4046

+ 18 - 1
apis/externalsecrets/v1alpha1/secretstore_vault_types.go

@@ -82,6 +82,11 @@ type VaultAuth struct {
 	// the LDAP authentication method
 	// the LDAP authentication method
 	// +optional
 	// +optional
 	Ldap *VaultLdapAuth `json:"ldap,omitempty"`
 	Ldap *VaultLdapAuth `json:"ldap,omitempty"`
+
+	// Jwt authenticates with Vault by passing role and JWT token using the
+	// JWT/OIDC authentication method
+	// +optional
+	Jwt *VaultJwtAuth `json:"jwt,omitempty"`
 }
 }
 
 
 // VaultAppRole authenticates with Vault using the App Role auth mechanism,
 // VaultAppRole authenticates with Vault using the App Role auth mechanism,
@@ -140,5 +145,17 @@ type VaultLdapAuth struct {
 	// SecretRef to a key in a Secret resource containing password for the LDAP
 	// SecretRef to a key in a Secret resource containing password for the LDAP
 	// user used to authenticate with Vault using the LDAP authentication
 	// user used to authenticate with Vault using the LDAP authentication
 	// method
 	// method
-	SecretRef *esmeta.SecretKeySelector `json:"tokenSecretRef,omitempty"`
+	SecretRef esmeta.SecretKeySelector `json:"tokenSecretRef,omitempty"`
+}
+
+// VaultJwtAuth authenticates with Vault using the JWT/OIDC authentication
+// method, with the role name and token stored in a Kubernetes Secret resource.
+type VaultJwtAuth struct {
+	// Role is a JWT role to authenticate using the JWT/OIDC Vault
+	// authentication method
+	Role string `json:"role"`
+
+	// SecretRef to a key in a Secret resource containing JWT token to
+	// authenticate with Vault using the JWT/OIDC authentication method
+	SecretRef esmeta.SecretKeySelector `json:"tokenSecretRef,omitempty"`
 }
 }

+ 22 - 5
apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

@@ -572,6 +572,11 @@ func (in *VaultAuth) DeepCopyInto(out *VaultAuth) {
 		*out = new(VaultLdapAuth)
 		*out = new(VaultLdapAuth)
 		(*in).DeepCopyInto(*out)
 		(*in).DeepCopyInto(*out)
 	}
 	}
+	if in.Jwt != nil {
+		in, out := &in.Jwt, &out.Jwt
+		*out = new(VaultJwtAuth)
+		(*in).DeepCopyInto(*out)
+	}
 }
 }
 
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultAuth.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultAuth.
@@ -585,6 +590,22 @@ func (in *VaultAuth) DeepCopy() *VaultAuth {
 }
 }
 
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VaultJwtAuth) DeepCopyInto(out *VaultJwtAuth) {
+	*out = *in
+	in.SecretRef.DeepCopyInto(&out.SecretRef)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultJwtAuth.
+func (in *VaultJwtAuth) DeepCopy() *VaultJwtAuth {
+	if in == nil {
+		return nil
+	}
+	out := new(VaultJwtAuth)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *VaultKubernetesAuth) DeepCopyInto(out *VaultKubernetesAuth) {
 func (in *VaultKubernetesAuth) DeepCopyInto(out *VaultKubernetesAuth) {
 	*out = *in
 	*out = *in
 	if in.ServiceAccountRef != nil {
 	if in.ServiceAccountRef != nil {
@@ -612,11 +633,7 @@ func (in *VaultKubernetesAuth) DeepCopy() *VaultKubernetesAuth {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *VaultLdapAuth) DeepCopyInto(out *VaultLdapAuth) {
 func (in *VaultLdapAuth) DeepCopyInto(out *VaultLdapAuth) {
 	*out = *in
 	*out = *in
-	if in.SecretRef != nil {
-		in, out := &in.SecretRef, &out.SecretRef
-		*out = new(metav1.SecretKeySelector)
-		(*in).DeepCopyInto(*out)
-	}
+	in.SecretRef.DeepCopyInto(&out.SecretRef)
 }
 }
 
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultLdapAuth.
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultLdapAuth.

+ 35 - 0
deploy/crds/external-secrets.io_clustersecretstores.yaml

@@ -189,6 +189,41 @@ spec:
                             - roleId
                             - roleId
                             - secretRef
                             - secretRef
                             type: object
                             type: object
+                          jwt:
+                            description: Jwt authenticates with Vault by passing role
+                              and JWT token using the JWT/OIDC authentication method
+                            properties:
+                              role:
+                                description: Role is a JWT role to authenticate using
+                                  the JWT/OIDC Vault authentication method
+                                type: string
+                              tokenSecretRef:
+                                description: SecretRef to a key in a Secret resource
+                                  containing JWT token to authenticate with Vault
+                                  using the LDAP authentication method
+                                properties:
+                                  key:
+                                    description: The key of the entry in the Secret
+                                      resource's `data` field to be used. Some instances
+                                      of this field may be defaulted, in others it
+                                      may be required.
+                                    type: string
+                                  name:
+                                    description: The name of the Secret resource being
+                                      referred to.
+                                    type: string
+                                  namespace:
+                                    description: Namespace of the resource being referred
+                                      to. Ignored if referent is not cluster-scoped.
+                                      cluster-scoped defaults to the namespace of
+                                      the referent.
+                                    type: string
+                                required:
+                                - name
+                                type: object
+                            required:
+                            - role
+                            type: object
                           kubernetes:
                           kubernetes:
                             description: Kubernetes authenticates with Vault by passing
                             description: Kubernetes authenticates with Vault by passing
                               the ServiceAccount token stored in the named Secret
                               the ServiceAccount token stored in the named Secret

+ 35 - 0
deploy/crds/external-secrets.io_secretstores.yaml

@@ -189,6 +189,41 @@ spec:
                             - roleId
                             - roleId
                             - secretRef
                             - secretRef
                             type: object
                             type: object
+                          jwt:
+                            description: Jwt authenticates with Vault by passing role
+                              and JWT token using the JWT/OIDC authentication method
+                            properties:
+                              role:
+                                description: Role is a JWT role to authenticate using
+                                  the JWT/OIDC Vault authentication method
+                                type: string
+                              tokenSecretRef:
+                                description: SecretRef to a key in a Secret resource
+                                  containing JWT token to authenticate with Vault
+                                  using the LDAP authentication method
+                                properties:
+                                  key:
+                                    description: The key of the entry in the Secret
+                                      resource's `data` field to be used. Some instances
+                                      of this field may be defaulted, in others it
+                                      may be required.
+                                    type: string
+                                  name:
+                                    description: The name of the Secret resource being
+                                      referred to.
+                                    type: string
+                                  namespace:
+                                    description: Namespace of the resource being referred
+                                      to. Ignored if referent is not cluster-scoped.
+                                      cluster-scoped defaults to the namespace of
+                                      the referent.
+                                    type: string
+                                required:
+                                - name
+                                type: object
+                            required:
+                            - role
+                            type: object
                           kubernetes:
                           kubernetes:
                             description: Kubernetes authenticates with Vault by passing
                             description: Kubernetes authenticates with Vault by passing
                               the ServiceAccount token stored in the named Secret
                               the ServiceAccount token stored in the named Secret

+ 89 - 0
pkg/provider/vault/vault.go

@@ -257,6 +257,16 @@ func (v *client) setAuth(ctx context.Context, client Client) error {
 		return nil
 		return nil
 	}
 	}
 
 
+	ldapAuth := v.store.Auth.Ldap
+	if ldapAuth != nil {
+		token, err := v.requestTokenWithLdapAuth(ctx, client, ldapAuth)
+		if err != nil {
+			return err
+		}
+		client.SetToken(token)
+		return nil
+	}
+
 	return errors.New(errAuthFormat)
 	return errors.New(errAuthFormat)
 }
 }
 
 
@@ -427,3 +437,82 @@ func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, client Clie
 
 
 	return token, nil
 	return token, nil
 }
 }
+
+func (v *client) requestTokenWithLdapAuth(ctx context.Context, client Client, ldapAuth *esv1alpha1.VaultLdapAuth) (string, error) {
+	username := strings.TrimSpace(ldapAuth.Username)
+
+	password, err := v.secretKeyRef(ctx, &ldapAuth.SecretRef)
+	if err != nil {
+		return "", err
+	}
+
+	parameters := map[string]string{
+		"password": password,
+	}
+	url := strings.Join([]string{"/v1", "auth", "ldap", "login", username}, "/")
+	request := client.NewRequest("POST", url)
+
+	err = request.SetJSONBody(parameters)
+	if err != nil {
+		return "", fmt.Errorf(errVaultReqParams, err)
+	}
+
+	resp, err := client.RawRequestWithContext(ctx, request)
+	if err != nil {
+		return "", fmt.Errorf(errVaultRequest, err)
+	}
+
+	defer resp.Body.Close()
+
+	vaultResult := vault.Secret{}
+	if err = resp.DecodeJSON(&vaultResult); err != nil {
+		return "", fmt.Errorf(errVaultResponse, err)
+	}
+
+	token, err := vaultResult.TokenID()
+	if err != nil {
+		return "", fmt.Errorf(errVaultToken, err)
+	}
+
+	return token, nil
+}
+
+func (v *client) requestTokenWithJwtAuth(ctx context.Context, client Client, jwtAuth *esv1alpha1.VaultJwtAuth) (string, error) {
+	role := strings.TrimSpace(jwtAuth.Role)
+
+	jwt, err := v.secretKeyRef(ctx, &jwtAuth.SecretRef)
+	if err != nil {
+		return "", err
+	}
+
+	parameters := map[string]string{
+		"role": role,
+		"jwt":  jwt,
+	}
+	url := strings.Join([]string{"/v1", "auth", "jwt", "login"}, "/")
+	request := client.NewRequest("POST", url)
+
+	err = request.SetJSONBody(parameters)
+	if err != nil {
+		return "", fmt.Errorf(errVaultReqParams, err)
+	}
+
+	resp, err := client.RawRequestWithContext(ctx, request)
+	if err != nil {
+		return "", fmt.Errorf(errVaultRequest, err)
+	}
+
+	defer resp.Body.Close()
+
+	vaultResult := vault.Secret{}
+	if err = resp.DecodeJSON(&vaultResult); err != nil {
+		return "", fmt.Errorf(errVaultResponse, err)
+	}
+
+	token, err := vaultResult.TokenID()
+	if err != nil {
+		return "", fmt.Errorf(errVaultToken, err)
+	}
+
+	return token, nil
+}