Skip to content
This repository has been archived by the owner on Jul 5, 2021. It is now read-only.

Commit

Permalink
#150 Implement LDAP and JWT/OIDC auth methods
Browse files Browse the repository at this point in the history
  • Loading branch information
vladarts committed May 13, 2021
1 parent 704e7a7 commit e4d8fb4
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 6 deletions.
19 changes: 18 additions & 1 deletion apis/externalsecrets/v1alpha1/secretstore_vault_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ type VaultAuth struct {
// the LDAP authentication method
// +optional
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,
Expand Down Expand Up @@ -140,5 +145,17 @@ type VaultLdapAuth struct {
// SecretRef to a key in a Secret resource containing password for the LDAP
// user used to authenticate with Vault using the LDAP authentication
// 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"`
}
27 changes: 22 additions & 5 deletions apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions deploy/crds/external-secrets.io_clustersecretstores.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,41 @@ spec:
- roleId
- secretRef
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:
description: Kubernetes authenticates with Vault by passing
the ServiceAccount token stored in the named Secret
Expand Down
35 changes: 35 additions & 0 deletions deploy/crds/external-secrets.io_secretstores.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,41 @@ spec:
- roleId
- secretRef
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:
description: Kubernetes authenticates with Vault by passing
the ServiceAccount token stored in the named Secret
Expand Down
89 changes: 89 additions & 0 deletions pkg/provider/vault/vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ func (v *client) setAuth(ctx context.Context, client Client) error {
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)
}

Expand Down Expand Up @@ -427,3 +437,82 @@ func (v *client) requestTokenWithKubernetesAuth(ctx context.Context, client Clie

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
}

0 comments on commit e4d8fb4

Please sign in to comment.