mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
✨ Enabling Vault IAM auth (#2208)
* Enabling Vault IAM auth Signed-off-by: Gaurav Dasson <gaurav.dasson@gmail.com> * Adding spec Signed-off-by: Gaurav Dasson <gaurav.dasson@gmail.com> * Adding test cases and decoupling vault provider from aws for iam auth Signed-off-by: Gaurav Dasson <gaurav.dasson@gmail.com> * Fixing comments Signed-off-by: Gaurav Dasson <gaurav.dasson@gmail.com> * Fixing linter issues Signed-off-by: Gaurav Dasson <gaurav.dasson@gmail.com> * Fixing the check-diff errors Signed-off-by: Gaurav Dasson <gaurav.dasson@gmail.com> * Adding support for assumeRole operations when using static creds Signed-off-by: Gaurav Dasson <gdasson@Gauravs-Mac-mini.local> * Bumping the dependencies to fix the go.mod/go.sum conflicts Signed-off-by: Gaurav Dasson <gdasson@Gauravs-Mac-mini.local> * Bumping up e2e go mod files Signed-off-by: Gaurav Dasson <gaurav.dasson@gmail.com> --------- Signed-off-by: Gaurav Dasson <gaurav.dasson@gmail.com>
This commit is contained in:
parent
f6475d63b0
commit
7b8fef2c18
21 changed files with 1854 additions and 6 deletions
|
@ -112,6 +112,11 @@ type VaultAuth struct {
|
|||
// Cert authentication method
|
||||
// +optional
|
||||
Cert *VaultCertAuth `json:"cert,omitempty"`
|
||||
|
||||
// Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials
|
||||
// AWS IAM authentication method
|
||||
// +optional
|
||||
Iam *VaultIamAuth `json:"iam,omitempty"`
|
||||
}
|
||||
|
||||
// VaultAppRole authenticates with Vault using the App Role auth mechanism,
|
||||
|
@ -178,6 +183,37 @@ type VaultLdapAuth struct {
|
|||
SecretRef esmeta.SecretKeySelector `json:"secretRef,omitempty"`
|
||||
}
|
||||
|
||||
// VaultAwsAuth tells the controller how to do authentication with aws.
|
||||
// Only one of secretRef or jwt can be specified.
|
||||
// if none is specified the controller will try to load credentials from its own service account assuming it is IRSA enabled.
|
||||
type VaultAwsAuth struct {
|
||||
// +optional
|
||||
SecretRef *VaultAwsAuthSecretRef `json:"secretRef,omitempty"`
|
||||
// +optional
|
||||
JWTAuth *VaultAwsJWTAuth `json:"jwt,omitempty"`
|
||||
}
|
||||
|
||||
// VaultAWSAuthSecretRef holds secret references for AWS credentials
|
||||
// both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate.
|
||||
type VaultAwsAuthSecretRef struct {
|
||||
// The AccessKeyID is used for authentication
|
||||
AccessKeyID esmeta.SecretKeySelector `json:"accessKeyIDSecretRef,omitempty"`
|
||||
|
||||
// The SecretAccessKey is used for authentication
|
||||
SecretAccessKey esmeta.SecretKeySelector `json:"secretAccessKeySecretRef,omitempty"`
|
||||
|
||||
// The SessionToken used for authentication
|
||||
// This must be defined if AccessKeyID and SecretAccessKey are temporary credentials
|
||||
// see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html
|
||||
// +Optional
|
||||
SessionToken *esmeta.SecretKeySelector `json:"sessionTokenSecretRef,omitempty"`
|
||||
}
|
||||
|
||||
// Authenticate against AWS using service account tokens.
|
||||
type VaultAwsJWTAuth struct {
|
||||
ServiceAccountRef *esmeta.ServiceAccountSelector `json:"serviceAccountRef,omitempty"`
|
||||
}
|
||||
|
||||
// VaultKubernetesServiceAccountTokenAuth authenticates with Vault using a temporary
|
||||
// Kubernetes service account token retrieved by the `TokenRequest` API.
|
||||
type VaultKubernetesServiceAccountTokenAuth struct {
|
||||
|
@ -237,3 +273,26 @@ type VaultCertAuth struct {
|
|||
// authenticate with Vault using the Cert authentication method
|
||||
SecretRef esmeta.SecretKeySelector `json:"secretRef,omitempty"`
|
||||
}
|
||||
|
||||
// VaultIamAuth authenticates with Vault using the Vault's AWS IAM authentication method. Refer: https://developer.hashicorp.com/vault/docs/auth/aws
|
||||
type VaultIamAuth struct {
|
||||
|
||||
// Path where the AWS auth method is enabled in Vault, e.g: "aws"
|
||||
Path string `json:"path,omitempty"`
|
||||
// AWS region
|
||||
Region string `json:"region,omitempty"`
|
||||
// This is the AWS role to be assumed before talking to vault
|
||||
AWSIAMRole string `json:"role,omitempty"`
|
||||
// Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine
|
||||
Role string `json:"vaultRole"`
|
||||
// AWS External ID set on assumed IAM roles
|
||||
ExternalID string `json:"externalID,omitempty"`
|
||||
// X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws
|
||||
VaultAWSIAMServerID string `json:"vaultAwsIamServerID,omitempty"`
|
||||
// Specify credentials in a Secret object
|
||||
// +optional
|
||||
SecretRef *VaultAwsAuthSecretRef `json:"secretRef,omitempty"`
|
||||
// Specify a service account with IRSA enabled
|
||||
// +optional
|
||||
JWTAuth *VaultAwsJWTAuth `json:"jwt,omitempty"`
|
||||
}
|
||||
|
|
|
@ -2051,6 +2051,11 @@ func (in *VaultAuth) DeepCopyInto(out *VaultAuth) {
|
|||
*out = new(VaultCertAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Iam != nil {
|
||||
in, out := &in.Iam, &out.Iam
|
||||
*out = new(VaultIamAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultAuth.
|
||||
|
@ -2063,6 +2068,73 @@ func (in *VaultAuth) DeepCopy() *VaultAuth {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *VaultAwsAuth) DeepCopyInto(out *VaultAwsAuth) {
|
||||
*out = *in
|
||||
if in.SecretRef != nil {
|
||||
in, out := &in.SecretRef, &out.SecretRef
|
||||
*out = new(VaultAwsAuthSecretRef)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.JWTAuth != nil {
|
||||
in, out := &in.JWTAuth, &out.JWTAuth
|
||||
*out = new(VaultAwsJWTAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultAwsAuth.
|
||||
func (in *VaultAwsAuth) DeepCopy() *VaultAwsAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(VaultAwsAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *VaultAwsAuthSecretRef) DeepCopyInto(out *VaultAwsAuthSecretRef) {
|
||||
*out = *in
|
||||
in.AccessKeyID.DeepCopyInto(&out.AccessKeyID)
|
||||
in.SecretAccessKey.DeepCopyInto(&out.SecretAccessKey)
|
||||
if in.SessionToken != nil {
|
||||
in, out := &in.SessionToken, &out.SessionToken
|
||||
*out = new(metav1.SecretKeySelector)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultAwsAuthSecretRef.
|
||||
func (in *VaultAwsAuthSecretRef) DeepCopy() *VaultAwsAuthSecretRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(VaultAwsAuthSecretRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *VaultAwsJWTAuth) DeepCopyInto(out *VaultAwsJWTAuth) {
|
||||
*out = *in
|
||||
if in.ServiceAccountRef != nil {
|
||||
in, out := &in.ServiceAccountRef, &out.ServiceAccountRef
|
||||
*out = new(metav1.ServiceAccountSelector)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultAwsJWTAuth.
|
||||
func (in *VaultAwsJWTAuth) DeepCopy() *VaultAwsJWTAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(VaultAwsJWTAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *VaultCertAuth) DeepCopyInto(out *VaultCertAuth) {
|
||||
*out = *in
|
||||
|
@ -2080,6 +2152,31 @@ func (in *VaultCertAuth) DeepCopy() *VaultCertAuth {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *VaultIamAuth) DeepCopyInto(out *VaultIamAuth) {
|
||||
*out = *in
|
||||
if in.SecretRef != nil {
|
||||
in, out := &in.SecretRef, &out.SecretRef
|
||||
*out = new(VaultAwsAuthSecretRef)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.JWTAuth != nil {
|
||||
in, out := &in.JWTAuth, &out.JWTAuth
|
||||
*out = new(VaultAwsJWTAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultIamAuth.
|
||||
func (in *VaultIamAuth) DeepCopy() *VaultIamAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(VaultIamAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -3003,6 +3003,135 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
type: object
|
||||
iam:
|
||||
description: Iam authenticates with vault by passing a
|
||||
special AWS request signed with AWS IAM credentials
|
||||
AWS IAM authentication method
|
||||
properties:
|
||||
externalID:
|
||||
description: AWS External ID set on assumed IAM roles
|
||||
type: string
|
||||
jwt:
|
||||
description: Specify a service account with IRSA enabled
|
||||
properties:
|
||||
serviceAccountRef:
|
||||
description: A reference to a ServiceAccount resource.
|
||||
properties:
|
||||
audiences:
|
||||
description: Audience specifies the `aud`
|
||||
claim for the service account token If the
|
||||
service account uses a well-known annotation
|
||||
for e.g. IRSA or GCP Workload Identity then
|
||||
this audiences will be appended to the list
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
description: The name of the ServiceAccount
|
||||
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
|
||||
type: object
|
||||
path:
|
||||
description: 'Path where the AWS auth method is enabled
|
||||
in Vault, e.g: "aws"'
|
||||
type: string
|
||||
region:
|
||||
description: AWS region
|
||||
type: string
|
||||
role:
|
||||
description: This is the AWS role to be assumed before
|
||||
talking to vault
|
||||
type: string
|
||||
secretRef:
|
||||
description: Specify credentials in a Secret object
|
||||
properties:
|
||||
accessKeyIDSecretRef:
|
||||
description: The AccessKeyID is used for authentication
|
||||
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
|
||||
type: object
|
||||
secretAccessKeySecretRef:
|
||||
description: The SecretAccessKey is used for authentication
|
||||
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
|
||||
type: object
|
||||
sessionTokenSecretRef:
|
||||
description: 'The SessionToken used for authentication
|
||||
This must be defined if AccessKeyID and SecretAccessKey
|
||||
are temporary credentials see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html'
|
||||
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
|
||||
type: object
|
||||
type: object
|
||||
vaultAwsIamServerID:
|
||||
description: 'X-Vault-AWS-IAM-Server-ID is an additional
|
||||
header used by Vault IAM auth method to mitigate
|
||||
against different types of replay attacks. More
|
||||
details here: https://developer.hashicorp.com/vault/docs/auth/aws'
|
||||
type: string
|
||||
vaultRole:
|
||||
description: Vault Role. In vault, a role describes
|
||||
an identity with a set of permissions, groups, or
|
||||
policies you want to attach a user of the secrets
|
||||
engine
|
||||
type: string
|
||||
required:
|
||||
- vaultRole
|
||||
type: object
|
||||
jwt:
|
||||
description: Jwt authenticates with Vault by passing role
|
||||
and JWT token using the JWT/OIDC authentication method
|
||||
|
|
|
@ -3003,6 +3003,135 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
type: object
|
||||
iam:
|
||||
description: Iam authenticates with vault by passing a
|
||||
special AWS request signed with AWS IAM credentials
|
||||
AWS IAM authentication method
|
||||
properties:
|
||||
externalID:
|
||||
description: AWS External ID set on assumed IAM roles
|
||||
type: string
|
||||
jwt:
|
||||
description: Specify a service account with IRSA enabled
|
||||
properties:
|
||||
serviceAccountRef:
|
||||
description: A reference to a ServiceAccount resource.
|
||||
properties:
|
||||
audiences:
|
||||
description: Audience specifies the `aud`
|
||||
claim for the service account token If the
|
||||
service account uses a well-known annotation
|
||||
for e.g. IRSA or GCP Workload Identity then
|
||||
this audiences will be appended to the list
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
description: The name of the ServiceAccount
|
||||
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
|
||||
type: object
|
||||
path:
|
||||
description: 'Path where the AWS auth method is enabled
|
||||
in Vault, e.g: "aws"'
|
||||
type: string
|
||||
region:
|
||||
description: AWS region
|
||||
type: string
|
||||
role:
|
||||
description: This is the AWS role to be assumed before
|
||||
talking to vault
|
||||
type: string
|
||||
secretRef:
|
||||
description: Specify credentials in a Secret object
|
||||
properties:
|
||||
accessKeyIDSecretRef:
|
||||
description: The AccessKeyID is used for authentication
|
||||
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
|
||||
type: object
|
||||
secretAccessKeySecretRef:
|
||||
description: The SecretAccessKey is used for authentication
|
||||
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
|
||||
type: object
|
||||
sessionTokenSecretRef:
|
||||
description: 'The SessionToken used for authentication
|
||||
This must be defined if AccessKeyID and SecretAccessKey
|
||||
are temporary credentials see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html'
|
||||
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
|
||||
type: object
|
||||
type: object
|
||||
vaultAwsIamServerID:
|
||||
description: 'X-Vault-AWS-IAM-Server-ID is an additional
|
||||
header used by Vault IAM auth method to mitigate
|
||||
against different types of replay attacks. More
|
||||
details here: https://developer.hashicorp.com/vault/docs/auth/aws'
|
||||
type: string
|
||||
vaultRole:
|
||||
description: Vault Role. In vault, a role describes
|
||||
an identity with a set of permissions, groups, or
|
||||
policies you want to attach a user of the secrets
|
||||
engine
|
||||
type: string
|
||||
required:
|
||||
- vaultRole
|
||||
type: object
|
||||
jwt:
|
||||
description: Jwt authenticates with Vault by passing role
|
||||
and JWT token using the JWT/OIDC authentication method
|
||||
|
|
|
@ -139,6 +139,134 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
type: object
|
||||
iam:
|
||||
description: Iam authenticates with vault by passing a special
|
||||
AWS request signed with AWS IAM credentials AWS IAM authentication
|
||||
method
|
||||
properties:
|
||||
externalID:
|
||||
description: AWS External ID set on assumed IAM roles
|
||||
type: string
|
||||
jwt:
|
||||
description: Specify a service account with IRSA enabled
|
||||
properties:
|
||||
serviceAccountRef:
|
||||
description: A reference to a ServiceAccount resource.
|
||||
properties:
|
||||
audiences:
|
||||
description: Audience specifies the `aud` claim
|
||||
for the service account token If the service
|
||||
account uses a well-known annotation for e.g.
|
||||
IRSA or GCP Workload Identity then this audiences
|
||||
will be appended to the list
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
description: The name of the ServiceAccount 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
|
||||
type: object
|
||||
path:
|
||||
description: 'Path where the AWS auth method is enabled
|
||||
in Vault, e.g: "aws"'
|
||||
type: string
|
||||
region:
|
||||
description: AWS region
|
||||
type: string
|
||||
role:
|
||||
description: This is the AWS role to be assumed before
|
||||
talking to vault
|
||||
type: string
|
||||
secretRef:
|
||||
description: Specify credentials in a Secret object
|
||||
properties:
|
||||
accessKeyIDSecretRef:
|
||||
description: The AccessKeyID is used for authentication
|
||||
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
|
||||
type: object
|
||||
secretAccessKeySecretRef:
|
||||
description: The SecretAccessKey is used for authentication
|
||||
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
|
||||
type: object
|
||||
sessionTokenSecretRef:
|
||||
description: 'The SessionToken used for authentication
|
||||
This must be defined if AccessKeyID and SecretAccessKey
|
||||
are temporary credentials see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html'
|
||||
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
|
||||
type: object
|
||||
type: object
|
||||
vaultAwsIamServerID:
|
||||
description: 'X-Vault-AWS-IAM-Server-ID is an additional
|
||||
header used by Vault IAM auth method to mitigate against
|
||||
different types of replay attacks. More details here:
|
||||
https://developer.hashicorp.com/vault/docs/auth/aws'
|
||||
type: string
|
||||
vaultRole:
|
||||
description: Vault Role. In vault, a role describes an
|
||||
identity with a set of permissions, groups, or policies
|
||||
you want to attach a user of the secrets engine
|
||||
type: string
|
||||
required:
|
||||
- vaultRole
|
||||
type: object
|
||||
jwt:
|
||||
description: Jwt authenticates with Vault by passing role
|
||||
and JWT token using the JWT/OIDC authentication method
|
||||
|
|
|
@ -2656,6 +2656,94 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
type: object
|
||||
iam:
|
||||
description: Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials AWS IAM authentication method
|
||||
properties:
|
||||
externalID:
|
||||
description: AWS External ID set on assumed IAM roles
|
||||
type: string
|
||||
jwt:
|
||||
description: Specify a service account with IRSA enabled
|
||||
properties:
|
||||
serviceAccountRef:
|
||||
description: A reference to a ServiceAccount resource.
|
||||
properties:
|
||||
audiences:
|
||||
description: Audience specifies the `aud` claim for the service account token If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity then this audiences will be appended to the list
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
description: The name of the ServiceAccount 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
|
||||
type: object
|
||||
path:
|
||||
description: 'Path where the AWS auth method is enabled in Vault, e.g: "aws"'
|
||||
type: string
|
||||
region:
|
||||
description: AWS region
|
||||
type: string
|
||||
role:
|
||||
description: This is the AWS role to be assumed before talking to vault
|
||||
type: string
|
||||
secretRef:
|
||||
description: Specify credentials in a Secret object
|
||||
properties:
|
||||
accessKeyIDSecretRef:
|
||||
description: The AccessKeyID is used for authentication
|
||||
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
|
||||
type: object
|
||||
secretAccessKeySecretRef:
|
||||
description: The SecretAccessKey is used for authentication
|
||||
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
|
||||
type: object
|
||||
sessionTokenSecretRef:
|
||||
description: 'The SessionToken used for authentication This must be defined if AccessKeyID and SecretAccessKey are temporary credentials see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html'
|
||||
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
|
||||
type: object
|
||||
type: object
|
||||
vaultAwsIamServerID:
|
||||
description: 'X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws'
|
||||
type: string
|
||||
vaultRole:
|
||||
description: Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine
|
||||
type: string
|
||||
required:
|
||||
- vaultRole
|
||||
type: object
|
||||
jwt:
|
||||
description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method
|
||||
properties:
|
||||
|
@ -6113,6 +6201,94 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
type: object
|
||||
iam:
|
||||
description: Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials AWS IAM authentication method
|
||||
properties:
|
||||
externalID:
|
||||
description: AWS External ID set on assumed IAM roles
|
||||
type: string
|
||||
jwt:
|
||||
description: Specify a service account with IRSA enabled
|
||||
properties:
|
||||
serviceAccountRef:
|
||||
description: A reference to a ServiceAccount resource.
|
||||
properties:
|
||||
audiences:
|
||||
description: Audience specifies the `aud` claim for the service account token If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity then this audiences will be appended to the list
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
description: The name of the ServiceAccount 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
|
||||
type: object
|
||||
path:
|
||||
description: 'Path where the AWS auth method is enabled in Vault, e.g: "aws"'
|
||||
type: string
|
||||
region:
|
||||
description: AWS region
|
||||
type: string
|
||||
role:
|
||||
description: This is the AWS role to be assumed before talking to vault
|
||||
type: string
|
||||
secretRef:
|
||||
description: Specify credentials in a Secret object
|
||||
properties:
|
||||
accessKeyIDSecretRef:
|
||||
description: The AccessKeyID is used for authentication
|
||||
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
|
||||
type: object
|
||||
secretAccessKeySecretRef:
|
||||
description: The SecretAccessKey is used for authentication
|
||||
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
|
||||
type: object
|
||||
sessionTokenSecretRef:
|
||||
description: 'The SessionToken used for authentication This must be defined if AccessKeyID and SecretAccessKey are temporary credentials see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html'
|
||||
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
|
||||
type: object
|
||||
type: object
|
||||
vaultAwsIamServerID:
|
||||
description: 'X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws'
|
||||
type: string
|
||||
vaultRole:
|
||||
description: Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine
|
||||
type: string
|
||||
required:
|
||||
- vaultRole
|
||||
type: object
|
||||
jwt:
|
||||
description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method
|
||||
properties:
|
||||
|
@ -7154,6 +7330,94 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
type: object
|
||||
iam:
|
||||
description: Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials AWS IAM authentication method
|
||||
properties:
|
||||
externalID:
|
||||
description: AWS External ID set on assumed IAM roles
|
||||
type: string
|
||||
jwt:
|
||||
description: Specify a service account with IRSA enabled
|
||||
properties:
|
||||
serviceAccountRef:
|
||||
description: A reference to a ServiceAccount resource.
|
||||
properties:
|
||||
audiences:
|
||||
description: Audience specifies the `aud` claim for the service account token If the service account uses a well-known annotation for e.g. IRSA or GCP Workload Identity then this audiences will be appended to the list
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
name:
|
||||
description: The name of the ServiceAccount 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
|
||||
type: object
|
||||
path:
|
||||
description: 'Path where the AWS auth method is enabled in Vault, e.g: "aws"'
|
||||
type: string
|
||||
region:
|
||||
description: AWS region
|
||||
type: string
|
||||
role:
|
||||
description: This is the AWS role to be assumed before talking to vault
|
||||
type: string
|
||||
secretRef:
|
||||
description: Specify credentials in a Secret object
|
||||
properties:
|
||||
accessKeyIDSecretRef:
|
||||
description: The AccessKeyID is used for authentication
|
||||
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
|
||||
type: object
|
||||
secretAccessKeySecretRef:
|
||||
description: The SecretAccessKey is used for authentication
|
||||
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
|
||||
type: object
|
||||
sessionTokenSecretRef:
|
||||
description: 'The SessionToken used for authentication This must be defined if AccessKeyID and SecretAccessKey are temporary credentials see: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html'
|
||||
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
|
||||
type: object
|
||||
type: object
|
||||
vaultAwsIamServerID:
|
||||
description: 'X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws'
|
||||
type: string
|
||||
vaultRole:
|
||||
description: Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine
|
||||
type: string
|
||||
required:
|
||||
- vaultRole
|
||||
type: object
|
||||
jwt:
|
||||
description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method
|
||||
properties:
|
||||
|
|
265
docs/api/spec.md
265
docs/api/spec.md
|
@ -5543,6 +5543,158 @@ VaultCertAuth
|
|||
Cert authentication method</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>iam</code></br>
|
||||
<em>
|
||||
<a href="#external-secrets.io/v1beta1.VaultIamAuth">
|
||||
VaultIamAuth
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Iam authenticates with vault by passing a special AWS request signed with AWS IAM credentials
|
||||
AWS IAM authentication method</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="external-secrets.io/v1beta1.VaultAwsAuth">VaultAwsAuth
|
||||
</h3>
|
||||
<p>
|
||||
<p>VaultAwsAuth tells the controller how to do authentication with aws.
|
||||
Only one of secretRef or jwt can be specified.
|
||||
if none is specified the controller will try to load credentials from its own service account assuming it is IRSA enabled.</p>
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>secretRef</code></br>
|
||||
<em>
|
||||
<a href="#external-secrets.io/v1beta1.VaultAwsAuthSecretRef">
|
||||
VaultAwsAuthSecretRef
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>jwt</code></br>
|
||||
<em>
|
||||
<a href="#external-secrets.io/v1beta1.VaultAwsJWTAuth">
|
||||
VaultAwsJWTAuth
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="external-secrets.io/v1beta1.VaultAwsAuthSecretRef">VaultAwsAuthSecretRef
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#external-secrets.io/v1beta1.VaultAwsAuth">VaultAwsAuth</a>,
|
||||
<a href="#external-secrets.io/v1beta1.VaultIamAuth">VaultIamAuth</a>)
|
||||
</p>
|
||||
<p>
|
||||
<p>VaultAWSAuthSecretRef holds secret references for AWS credentials
|
||||
both AccessKeyID and SecretAccessKey must be defined in order to properly authenticate.</p>
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>accessKeyIDSecretRef</code></br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#SecretKeySelector">
|
||||
External Secrets meta/v1.SecretKeySelector
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>The AccessKeyID is used for authentication</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>secretAccessKeySecretRef</code></br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#SecretKeySelector">
|
||||
External Secrets meta/v1.SecretKeySelector
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>The SecretAccessKey is used for authentication</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>sessionTokenSecretRef</code></br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#SecretKeySelector">
|
||||
External Secrets meta/v1.SecretKeySelector
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>The SessionToken used for authentication
|
||||
This must be defined if AccessKeyID and SecretAccessKey are temporary credentials
|
||||
see: <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html">https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="external-secrets.io/v1beta1.VaultAwsJWTAuth">VaultAwsJWTAuth
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#external-secrets.io/v1beta1.VaultAwsAuth">VaultAwsAuth</a>,
|
||||
<a href="#external-secrets.io/v1beta1.VaultIamAuth">VaultIamAuth</a>)
|
||||
</p>
|
||||
<p>
|
||||
<p>Authenticate against AWS using service account tokens.</p>
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>serviceAccountRef</code></br>
|
||||
<em>
|
||||
<a href="https://pkg.go.dev/github.com/external-secrets/external-secrets/apis/meta/v1#ServiceAccountSelector">
|
||||
External Secrets meta/v1.ServiceAccountSelector
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="external-secrets.io/v1beta1.VaultCertAuth">VaultCertAuth
|
||||
|
@ -5594,6 +5746,119 @@ authenticate with Vault using the Cert authentication method</p>
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="external-secrets.io/v1beta1.VaultIamAuth">VaultIamAuth
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#external-secrets.io/v1beta1.VaultAuth">VaultAuth</a>)
|
||||
</p>
|
||||
<p>
|
||||
<p>VaultIamAuth authenticates with Vault using the Vault’s AWS IAM authentication method. Refer: <a href="https://developer.hashicorp.com/vault/docs/auth/aws">https://developer.hashicorp.com/vault/docs/auth/aws</a></p>
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>path</code></br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Path where the AWS auth method is enabled in Vault, e.g: “aws”</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>region</code></br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>AWS region</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>role</code></br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>This is the AWS role to be assumed before talking to vault</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>vaultRole</code></br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>externalID</code></br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>AWS External ID set on assumed IAM roles</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>vaultAwsIamServerID</code></br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>X-Vault-AWS-IAM-Server-ID is an additional header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: <a href="https://developer.hashicorp.com/vault/docs/auth/aws">https://developer.hashicorp.com/vault/docs/auth/aws</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>secretRef</code></br>
|
||||
<em>
|
||||
<a href="#external-secrets.io/v1beta1.VaultAwsAuthSecretRef">
|
||||
VaultAwsAuthSecretRef
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Specify credentials in a Secret object</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>jwt</code></br>
|
||||
<em>
|
||||
<a href="#external-secrets.io/v1beta1.VaultAwsJWTAuth">
|
||||
VaultAwsJWTAuth
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Specify a service account with IRSA enabled</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="external-secrets.io/v1beta1.VaultJwtAuth">VaultJwtAuth
|
||||
</h3>
|
||||
<p>
|
||||
|
|
|
@ -271,8 +271,9 @@ We support five different modes for authentication:
|
|||
[token-based](https://www.vaultproject.io/docs/auth/token),
|
||||
[appRole](https://www.vaultproject.io/docs/auth/approle),
|
||||
[kubernetes-native](https://www.vaultproject.io/docs/auth/kubernetes),
|
||||
[ldap](https://www.vaultproject.io/docs/auth/ldap) and
|
||||
[jwt/oidc](https://www.vaultproject.io/docs/auth/jwt), each one comes with it's own
|
||||
[ldap](https://www.vaultproject.io/docs/auth/ldap),
|
||||
[jwt/oidc](https://www.vaultproject.io/docs/auth/jwt) and
|
||||
[awsAuth](https://developer.hashicorp.com/vault/docs/auth/aws), each one comes with it's own
|
||||
trade-offs. Depending on the authentication method you need to adapt your environment.
|
||||
|
||||
#### Token-based authentication
|
||||
|
@ -333,6 +334,54 @@ or `Kind=ClusterSecretStore` resource.
|
|||
```
|
||||
**NOTE:** In case of a `ClusterSecretStore`, Be sure to provide `namespace` in `secretRef` with the namespace where the secret resides.
|
||||
|
||||
#### AWS IAM authentication
|
||||
|
||||
[AWS IAM](https://developer.hashicorp.com/vault/docs/auth/aws) uses either a
|
||||
set of AWS Programmatic access credentials stored in a `Kind=Secret` and referenced by the
|
||||
`secretRef` or by getting the authentication token from an [IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) enabled service account
|
||||
|
||||
### Access Key ID & Secret Access Key
|
||||
You can store Access Key ID & Secret Access Key in a `Kind=Secret` and reference it from a SecretStore.
|
||||
|
||||
```yaml
|
||||
{% include 'vault-iam-store-static-creds.yaml' %}
|
||||
```
|
||||
|
||||
**NOTE:** In case of a `ClusterSecretStore`, Be sure to provide `namespace` in `accessKeyIDSecretRef`, `secretAccessKeySecretRef` with the namespaces where the secrets reside.
|
||||
|
||||
### EKS Service Account credentials
|
||||
|
||||
This feature lets you use short-lived service account tokens to authenticate with AWS.
|
||||
You must have [Service Account Volume Projection](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#service-account-token-volume-projection) enabled - it is by default on EKS. See [EKS guide](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html) on how to set up IAM roles for service accounts.
|
||||
|
||||
The big advantage of this approach is that ESO runs without any credentials.
|
||||
|
||||
```yaml
|
||||
{% include 'vault-iam-store-sa.yaml' %}
|
||||
```
|
||||
|
||||
Reference the service account from above in the Secret Store:
|
||||
|
||||
```yaml
|
||||
{% include 'vault-iam-store.yaml' %}
|
||||
```
|
||||
### Controller's Pod Identity
|
||||
|
||||
This is basicially a zero-configuration authentication approach that inherits the credentials from the controller's pod identity
|
||||
|
||||
This approach assumes that appropriate IRSA setup is done controller's pod (i.e. IRSA enabled IAM role is created appropriately and controller's service account is annotated appropriately with the annotation "eks.amazonaws.com/role-arn" to enable IRSA)
|
||||
|
||||
```yaml
|
||||
{% include 'vault-iam-store-controller-pod-identity.yaml' %}
|
||||
```
|
||||
|
||||
**NOTE:** In case of a `ClusterSecretStore`, Be sure to provide `namespace` for `serviceAccountRef` with the namespace where the service account resides.
|
||||
|
||||
```yaml
|
||||
{% include 'vault-jwt-store.yaml' %}
|
||||
```
|
||||
**NOTE:** In case of a `ClusterSecretStore`, Be sure to provide `namespace` in `secretRef` with the namespace where the secret resides.
|
||||
|
||||
### PushSecret
|
||||
Vault supports PushSecret features which allow you to sync a given kubernetes secret key into a hashicorp vault secret. In order to do so, it is expected that the secret key is a valid JSON object.
|
||||
|
||||
|
|
21
docs/snippets/vault-iam-store-controller-pod-identity.yaml
Normal file
21
docs/snippets/vault-iam-store-controller-pod-identity.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: vault-backend-aws-iam
|
||||
spec:
|
||||
provider:
|
||||
vault:
|
||||
server: "http://my.vault.server:8200"
|
||||
path: secret
|
||||
version: v2
|
||||
namespace: <vault_namespace>
|
||||
auth:
|
||||
iam:
|
||||
# Path where the AWS auth method is enabled in Vault, e.g: "aws/". Defaults to aws
|
||||
path: aws
|
||||
# AWS Region. Defaults to us-east-1
|
||||
region: us-east-1
|
||||
# Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine
|
||||
vaultRole: vault-role-for-aws-iam-auth
|
||||
# Optional. Placeholder to supply header X-Vault-AWS-IAM-Server-ID. It is an additional (optional) header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws
|
||||
vaultAwsIamServerID: example-vaultAwsIamServerID
|
7
docs/snippets/vault-iam-store-sa.yaml
Normal file
7
docs/snippets/vault-iam-store-sa.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
annotations:
|
||||
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-irsa-enabled-role
|
||||
name: my-serviceaccount
|
||||
namespace: default
|
33
docs/snippets/vault-iam-store-static-creds.yaml
Normal file
33
docs/snippets/vault-iam-store-static-creds.yaml
Normal file
|
@ -0,0 +1,33 @@
|
|||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: vault-backend-aws-iam
|
||||
spec:
|
||||
provider:
|
||||
vault:
|
||||
server: "http://my.vault.server:8200"
|
||||
path: secret
|
||||
version: v2
|
||||
namespace: <vault_namespace>
|
||||
auth:
|
||||
iam:
|
||||
# Path where the AWS auth method is enabled in Vault, e.g: "aws/". Defaults to aws
|
||||
path: aws
|
||||
# AWS Region. Defaults to us-east-1
|
||||
region: us-east-1
|
||||
# optional: assume role before fetching secrets
|
||||
role: arn:aws:iam::1234567890:role/role-a
|
||||
# Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine
|
||||
vaultRole: vault-role-for-aws-iam-auth
|
||||
# Optional. Placeholder to supply header X-Vault-AWS-IAM-Server-ID. It is an additional (optional) header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws
|
||||
vaultAwsIamServerID: example-vaultAwsIamServerID
|
||||
secretRef: #Use this method when you have static AWS creds.
|
||||
accessKeyIDSecretRef:
|
||||
name: vault-iam-creds-secret
|
||||
key: access-key
|
||||
secretAccessKeySecretRef:
|
||||
name: vault-iam-creds-secret
|
||||
key: secret-access-key
|
||||
sessionTokenSecretRef:
|
||||
name: vault-iam-creds-secret
|
||||
key: secret-session-token
|
24
docs/snippets/vault-iam-store.yaml
Normal file
24
docs/snippets/vault-iam-store.yaml
Normal file
|
@ -0,0 +1,24 @@
|
|||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: vault-backend-aws-iam
|
||||
spec:
|
||||
provider:
|
||||
vault:
|
||||
server: "http://my.vault.server:8200"
|
||||
path: secret
|
||||
version: v2
|
||||
namespace: <vault_namespace>
|
||||
auth:
|
||||
iam:
|
||||
# Path where the AWS auth method is enabled in Vault, e.g: "aws/". Defaults to aws
|
||||
path: aws
|
||||
# AWS Region. Defaults to us-east-1
|
||||
region: us-east-1
|
||||
# Vault Role. In vault, a role describes an identity with a set of permissions, groups, or policies you want to attach a user of the secrets engine
|
||||
vaultRole: vault-role-for-aws-iam-auth
|
||||
# Optional. Placeholder to supply header X-Vault-AWS-IAM-Server-ID. It is an additional (optional) header used by Vault IAM auth method to mitigate against different types of replay attacks. More details here: https://developer.hashicorp.com/vault/docs/auth/aws
|
||||
vaultAwsIamServerID: example-vaultAwsIamServerID
|
||||
jwt:
|
||||
serviceAccountRef:
|
||||
name: my-serviceaccount #Provide service account with IRSA enabled
|
|
@ -179,7 +179,6 @@ require (
|
|||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/robfig/cron v1.2.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
github.com/russross/blackfriday v1.5.2 // indirect
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
|
|
|
@ -853,7 +853,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
|
|||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
|
||||
github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
|
||||
|
|
5
go.mod
5
go.mod
|
@ -71,7 +71,9 @@ require (
|
|||
github.com/alibabacloud-go/tea-utils/v2 v2.0.1
|
||||
github.com/aliyun/credentials-go v1.2.7
|
||||
github.com/avast/retry-go/v4 v4.3.4
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/hashicorp/vault/api/auth/aws v0.4.0
|
||||
github.com/keeper-security/secrets-manager-go/core v1.5.0
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.6.1
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.16
|
||||
|
@ -90,6 +92,9 @@ require (
|
|||
github.com/clbanning/mxj/v2 v2.5.7 // indirect
|
||||
github.com/go-playground/validator/v10 v10.13.0 // indirect
|
||||
github.com/google/s2a-go v0.1.3 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
)
|
||||
|
||||
|
|
17
go.sum
17
go.sum
|
@ -154,6 +154,7 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
|
|||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/avast/retry-go/v4 v4.3.4 h1:pHLkL7jvCvP317I8Ge+Km2Yhntv3SdkJm7uekkqbKhM=
|
||||
github.com/avast/retry-go/v4 v4.3.4/go.mod h1:rv+Nla6Vk3/ilU0H51VHddWHiwimzX66yZ0JT6T+UvE=
|
||||
github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.41.13/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go v1.44.254 h1:8baW4yal2xGiM/Wm5/ZU10drS8sd+BVjMjPFjJx2ooc=
|
||||
github.com/aws/aws-sdk-go v1.44.254/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
|
@ -255,6 +256,7 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
|||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ=
|
||||
github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
|
@ -272,6 +274,8 @@ github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw
|
|||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2 h1:hXPcSazn8wKOfSb9y2m1bdgUMlDxVDarxh3lJVbC6JE=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
@ -381,6 +385,8 @@ github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUD
|
|||
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 h1:W9WN8p6moV1fjKLkeqEgkAMu5rauy9QeYDAmIaPuuiA=
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6/go.mod h1:MpCPSPGLDILGb4JMm94/mMi3YysIqsXzGCzkEZjcjXg=
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs=
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
|
||||
|
@ -389,6 +395,8 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9
|
|||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
|
@ -401,6 +409,8 @@ github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLO
|
|||
github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs=
|
||||
github.com/hashicorp/vault/api/auth/approle v0.4.0 h1:tjJHoUkPx8zRoFlFy86uvgg/1gpTnDPp0t0BYWTKjjw=
|
||||
github.com/hashicorp/vault/api/auth/approle v0.4.0/go.mod h1:D2gEpR0aS/F/MEcSjmhUlOsuK1RMVZojsnIQAEf0EV0=
|
||||
github.com/hashicorp/vault/api/auth/aws v0.4.0 h1:2Myo+XU3X5gQTtr3S+WGXcrLUa6iO4w97VzFFaaBOm8=
|
||||
github.com/hashicorp/vault/api/auth/aws v0.4.0/go.mod h1:CGm5PAXEREuYpszyA2ERQPFBSIUD+QTqXfKvdI2Gw/Q=
|
||||
github.com/hashicorp/vault/api/auth/kubernetes v0.4.0 h1:f6OIOF9012JIdqYvOeeewxhtQdJosnog2CHzh33j41s=
|
||||
github.com/hashicorp/vault/api/auth/kubernetes v0.4.0/go.mod h1:tMewM2hPyFNKP1EXdWbc0dUHHoS5V/0qS04BEaxuy78=
|
||||
github.com/hashicorp/vault/api/auth/ldap v0.4.0 h1:/P2HCNmcDY6s22JBXxVhr9noaFqPEQS2qwSnWIYezkc=
|
||||
|
@ -416,6 +426,7 @@ github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+h
|
|||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
|
@ -437,6 +448,7 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
|
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
|
@ -541,7 +553,9 @@ github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJf
|
|||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
|
@ -812,6 +826,7 @@ golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
309
pkg/provider/vault/iamauth/iamauth.go
Normal file
309
pkg/provider/vault/iamauth/iamauth.go
Normal file
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Mostly sourced from ~/external-secrets/pkg/provider/aws/auth
|
||||
package iamauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
"github.com/aws/aws-sdk-go/service/sts/stsiface"
|
||||
authv1 "k8s.io/api/authentication/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
k8scorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
kclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
ctrlcfg "sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
|
||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||
"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
|
||||
)
|
||||
|
||||
var (
|
||||
logger = ctrl.Log.WithName("provider").WithName("vault")
|
||||
)
|
||||
|
||||
const (
|
||||
roleARNAnnotation = "eks.amazonaws.com/role-arn"
|
||||
audienceAnnotation = "eks.amazonaws.com/audience"
|
||||
defaultTokenAudience = "sts.amazonaws.com"
|
||||
|
||||
STSEndpointEnv = "AWS_STS_ENDPOINT"
|
||||
AWSWebIdentityTokenFileEnvVar = "AWS_WEB_IDENTITY_TOKEN_FILE"
|
||||
|
||||
errInvalidClusterStoreMissingAKIDNamespace = "invalid ClusterSecretStore: missing AWS AccessKeyID Namespace"
|
||||
errInvalidClusterStoreMissingSAKNamespace = "invalid ClusterSecretStore: missing AWS SecretAccessKey Namespace"
|
||||
errFetchAKIDSecret = "could not fetch accessKeyID secret: %w"
|
||||
errFetchSAKSecret = "could not fetch SecretAccessKey secret: %w"
|
||||
errFetchSTSecret = "could not fetch SessionToken secret: %w"
|
||||
errMissingSAK = "missing SecretAccessKey"
|
||||
errMissingAKID = "missing AccessKeyID"
|
||||
)
|
||||
|
||||
// DefaultJWTProvider returns a credentials.Provider that calls the AssumeRoleWithWebidentity
|
||||
// controller-runtime/client does not support TokenRequest or other subresource APIs
|
||||
// so we need to construct our own client and use it to fetch tokens.
|
||||
func DefaultJWTProvider(name, namespace, roleArn string, aud []string, region string) (credentials.Provider, error) {
|
||||
cfg, err := ctrlcfg.GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clientset, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handlers := defaults.Handlers()
|
||||
handlers.Build.PushBack(request.WithAppendUserAgent("external-secrets"))
|
||||
awscfg := aws.NewConfig().WithEndpointResolver(ResolveEndpoint())
|
||||
if region != "" {
|
||||
awscfg.WithRegion(region)
|
||||
}
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: *awscfg,
|
||||
SharedConfigState: session.SharedConfigDisable,
|
||||
Handlers: handlers,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenFetcher := &authTokenFetcher{
|
||||
Namespace: namespace,
|
||||
Audiences: aud,
|
||||
ServiceAccount: name,
|
||||
k8sClient: clientset.CoreV1(),
|
||||
}
|
||||
|
||||
return stscreds.NewWebIdentityRoleProviderWithOptions(
|
||||
sts.New(sess), roleArn, "external-secrets-provider-vault", tokenFetcher), nil
|
||||
}
|
||||
|
||||
// ResolveEndpoint returns a ResolverFunc with
|
||||
// customizable endpoints.
|
||||
func ResolveEndpoint() endpoints.ResolverFunc {
|
||||
customEndpoints := make(map[string]string)
|
||||
if v := os.Getenv(STSEndpointEnv); v != "" {
|
||||
customEndpoints["sts"] = v
|
||||
}
|
||||
return ResolveEndpointWithServiceMap(customEndpoints)
|
||||
}
|
||||
|
||||
func ResolveEndpointWithServiceMap(customEndpoints map[string]string) endpoints.ResolverFunc {
|
||||
defaultResolver := endpoints.DefaultResolver()
|
||||
return func(service, region string, opts ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
|
||||
if ep, ok := customEndpoints[service]; ok {
|
||||
return endpoints.ResolvedEndpoint{
|
||||
URL: ep,
|
||||
}, nil
|
||||
}
|
||||
return defaultResolver.EndpointFor(service, region, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
// mostly taken from:
|
||||
// https://github.com/aws/secrets-store-csi-driver-provider-aws/blob/main/auth/auth.go#L140-L145
|
||||
|
||||
type authTokenFetcher struct {
|
||||
Namespace string
|
||||
// Audience is the token aud claim
|
||||
// which is verified by the aws oidc provider
|
||||
// see: https://github.com/external-secrets/external-secrets/issues/1251#issuecomment-1161745849
|
||||
Audiences []string
|
||||
ServiceAccount string
|
||||
k8sClient k8scorev1.CoreV1Interface
|
||||
}
|
||||
|
||||
// FetchToken satisfies the stscreds.TokenFetcher interface
|
||||
// it is used to generate service account tokens which are consumed by the aws sdk.
|
||||
func (p authTokenFetcher) FetchToken(ctx credentials.Context) ([]byte, error) {
|
||||
logger.V(1).Info("fetching token", "ns", p.Namespace, "sa", p.ServiceAccount)
|
||||
tokRsp, err := p.k8sClient.ServiceAccounts(p.Namespace).CreateToken(ctx, p.ServiceAccount, &authv1.TokenRequest{
|
||||
Spec: authv1.TokenRequestSpec{
|
||||
Audiences: p.Audiences,
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating service account token: %w", err)
|
||||
}
|
||||
return []byte(tokRsp.Status.Token), nil
|
||||
}
|
||||
|
||||
// CredsFromServiceAccount uses a Kubernetes Service Account to acquire temporary
|
||||
// credentials using aws.AssumeRoleWithWebIdentity. It will assume the role defined
|
||||
// in the ServiceAccount annotation.
|
||||
// If the ClusterSecretStore does not define a namespace it will use the namespace from the ExternalSecret (referentAuth).
|
||||
// If the ClusterSecretStore defines the namespace it will take precedence.
|
||||
func CredsFromServiceAccount(ctx context.Context, auth esv1beta1.VaultIamAuth, region string, isClusterKind bool, kube kclient.Client, namespace string, jwtProvider util.JwtProviderFactory) (*credentials.Credentials, error) {
|
||||
name := auth.JWTAuth.ServiceAccountRef.Name
|
||||
if isClusterKind && auth.JWTAuth.ServiceAccountRef.Namespace != nil {
|
||||
namespace = *auth.JWTAuth.ServiceAccountRef.Namespace
|
||||
}
|
||||
sa := v1.ServiceAccount{}
|
||||
err := kube.Get(ctx, types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
}, &sa)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// the service account is expected to have a well-known annotation
|
||||
// this is used as input to assumeRoleWithWebIdentity
|
||||
roleArn := sa.Annotations[roleARNAnnotation]
|
||||
if roleArn == "" {
|
||||
return nil, fmt.Errorf("an IAM role must be associated with service account %s (namespace: %s)", name, namespace)
|
||||
}
|
||||
|
||||
tokenAud := sa.Annotations[audienceAnnotation]
|
||||
if tokenAud == "" {
|
||||
tokenAud = defaultTokenAudience
|
||||
}
|
||||
audiences := []string{tokenAud}
|
||||
if len(auth.JWTAuth.ServiceAccountRef.Audiences) > 0 {
|
||||
audiences = append(audiences, auth.JWTAuth.ServiceAccountRef.Audiences...)
|
||||
}
|
||||
|
||||
jwtProv, err := jwtProvider(name, namespace, roleArn, audiences, region)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.V(1).Info("using credentials via service account", "role", roleArn, "region", region)
|
||||
return credentials.NewCredentials(jwtProv), nil
|
||||
}
|
||||
|
||||
func CredsFromControllerServiceAccount(ctx context.Context, saname, ns, region string, kube kclient.Client, jwtProvider util.JwtProviderFactory) (*credentials.Credentials, error) {
|
||||
name := saname
|
||||
nmspc := ns
|
||||
|
||||
sa := v1.ServiceAccount{}
|
||||
err := kube.Get(ctx, types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: nmspc,
|
||||
}, &sa)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// the service account is expected to have a well-known annotation
|
||||
// this is used as input to assumeRoleWithWebIdentity
|
||||
roleArn := sa.Annotations[roleARNAnnotation]
|
||||
if roleArn == "" {
|
||||
return nil, fmt.Errorf("an IAM role must be associated with service account %s (namespace: %s)", name, nmspc)
|
||||
}
|
||||
|
||||
tokenAud := sa.Annotations[audienceAnnotation]
|
||||
if tokenAud == "" {
|
||||
tokenAud = defaultTokenAudience
|
||||
}
|
||||
audiences := []string{tokenAud}
|
||||
|
||||
jwtProv, err := jwtProvider(name, nmspc, roleArn, audiences, region)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.V(1).Info("using credentials via service account", "role", roleArn, "region", region)
|
||||
return credentials.NewCredentials(jwtProv), nil
|
||||
}
|
||||
|
||||
// CredsFromSecretRef pulls access-key / secret-access-key from a secretRef to
|
||||
// construct a aws.Credentials object
|
||||
// The namespace of the external secret is used if the ClusterSecretStore does not specify a namespace (referentAuth)
|
||||
// If the ClusterSecretStore defines a namespace it will take precedence.
|
||||
func CredsFromSecretRef(ctx context.Context, auth esv1beta1.VaultIamAuth, isClusterKind bool, kube kclient.Client, namespace string) (*credentials.Credentials, error) {
|
||||
ke := kclient.ObjectKey{
|
||||
Name: auth.SecretRef.AccessKeyID.Name,
|
||||
Namespace: namespace,
|
||||
}
|
||||
if isClusterKind && auth.SecretRef.AccessKeyID.Namespace != nil {
|
||||
ke.Namespace = *auth.SecretRef.AccessKeyID.Namespace
|
||||
}
|
||||
akSecret := v1.Secret{}
|
||||
err := kube.Get(ctx, ke, &akSecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(errFetchAKIDSecret, err)
|
||||
}
|
||||
ke = kclient.ObjectKey{
|
||||
Name: auth.SecretRef.SecretAccessKey.Name,
|
||||
Namespace: namespace,
|
||||
}
|
||||
if isClusterKind && auth.SecretRef.SecretAccessKey.Namespace != nil {
|
||||
ke.Namespace = *auth.SecretRef.SecretAccessKey.Namespace
|
||||
}
|
||||
sakSecret := v1.Secret{}
|
||||
err = kube.Get(ctx, ke, &sakSecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(errFetchSAKSecret, err)
|
||||
}
|
||||
sak := string(sakSecret.Data[auth.SecretRef.SecretAccessKey.Key])
|
||||
aks := string(akSecret.Data[auth.SecretRef.AccessKeyID.Key])
|
||||
if sak == "" {
|
||||
return nil, fmt.Errorf(errMissingSAK)
|
||||
}
|
||||
if aks == "" {
|
||||
return nil, fmt.Errorf(errMissingAKID)
|
||||
}
|
||||
|
||||
var sessionToken string
|
||||
if auth.SecretRef.SessionToken != nil {
|
||||
ke = kclient.ObjectKey{
|
||||
Name: auth.SecretRef.SessionToken.Name,
|
||||
Namespace: namespace,
|
||||
}
|
||||
if isClusterKind && auth.SecretRef.SessionToken.Namespace != nil {
|
||||
ke.Namespace = *auth.SecretRef.SessionToken.Namespace
|
||||
}
|
||||
stSecret := v1.Secret{}
|
||||
err = kube.Get(ctx, ke, &stSecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(errFetchSTSecret, err)
|
||||
}
|
||||
sessionToken = string(stSecret.Data[auth.SecretRef.SessionToken.Key])
|
||||
}
|
||||
|
||||
return credentials.NewStaticCredentials(aks, sak, sessionToken), err
|
||||
}
|
||||
|
||||
type STSProvider func(*session.Session) stsiface.STSAPI
|
||||
|
||||
func DefaultSTSProvider(sess *session.Session) stsiface.STSAPI {
|
||||
return sts.New(sess)
|
||||
}
|
||||
|
||||
// getAWSSession returns the aws session or an error.
|
||||
func GetAWSSession(config *aws.Config) (*session.Session, error) {
|
||||
handlers := defaults.Handlers()
|
||||
handlers.Build.PushBack(request.WithAppendUserAgent("external-secrets"))
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: *config,
|
||||
Handlers: handlers,
|
||||
SharedConfigState: session.SharedConfigDisable,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sess, nil
|
||||
}
|
60
pkg/provider/vault/iamauth/iamauth_test.go
Normal file
60
pkg/provider/vault/iamauth/iamauth_test.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package iamauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/external-secrets/external-secrets/pkg/provider/util/fake"
|
||||
)
|
||||
|
||||
func TestTokenFetcher(t *testing.T) {
|
||||
tf := &authTokenFetcher{
|
||||
ServiceAccount: "foobar",
|
||||
Namespace: "example",
|
||||
k8sClient: fake.NewCreateTokenMock().WithToken("FAKETOKEN"),
|
||||
}
|
||||
token, err := tf.FetchToken(context.Background())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []byte("FAKETOKEN"), token)
|
||||
}
|
||||
|
||||
func TestResolver(t *testing.T) {
|
||||
tbl := []struct {
|
||||
env string
|
||||
service string
|
||||
url string
|
||||
}{
|
||||
{
|
||||
env: STSEndpointEnv,
|
||||
service: "sts",
|
||||
url: "http://sts.foo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, item := range tbl {
|
||||
t.Setenv(item.env, item.url)
|
||||
}
|
||||
|
||||
f := ResolveEndpoint()
|
||||
|
||||
for _, item := range tbl {
|
||||
ep, err := f.EndpointFor(item.service, "")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, item.url, ep.URL)
|
||||
}
|
||||
}
|
|
@ -17,9 +17,12 @@ package util
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
vault "github.com/hashicorp/vault/api"
|
||||
)
|
||||
|
||||
type JwtProviderFactory func(name, namespace, roleArn string, aud []string, region string) (credentials.Provider, error)
|
||||
|
||||
type Auth interface {
|
||||
Login(ctx context.Context, authMethod vault.AuthMethod) (*vault.Secret, error)
|
||||
}
|
||||
|
|
|
@ -28,9 +28,14 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
vault "github.com/hashicorp/vault/api"
|
||||
approle "github.com/hashicorp/vault/api/auth/approle"
|
||||
authaws "github.com/hashicorp/vault/api/auth/aws"
|
||||
authkubernetes "github.com/hashicorp/vault/api/auth/kubernetes"
|
||||
authldap "github.com/hashicorp/vault/api/auth/ldap"
|
||||
"github.com/spf13/pflag"
|
||||
|
@ -51,6 +56,7 @@ import (
|
|||
"github.com/external-secrets/external-secrets/pkg/feature"
|
||||
"github.com/external-secrets/external-secrets/pkg/find"
|
||||
"github.com/external-secrets/external-secrets/pkg/provider/metrics"
|
||||
vaultiamauth "github.com/external-secrets/external-secrets/pkg/provider/vault/iamauth"
|
||||
"github.com/external-secrets/external-secrets/pkg/provider/vault/util"
|
||||
"github.com/external-secrets/external-secrets/pkg/utils"
|
||||
)
|
||||
|
@ -64,7 +70,9 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
serviceAccTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
||||
serviceAccTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
||||
defaultAWSRegion = "us-east-1"
|
||||
defaultAWSAuthMountPath = "aws"
|
||||
|
||||
errVaultStore = "received invalid Vault SecretStore resource: %w"
|
||||
errVaultCacheCreate = "cannot create Vault client cache: %s"
|
||||
|
@ -87,6 +95,11 @@ const (
|
|||
errUnsupportedKvVersion = "cannot perform find operations with kv version v1"
|
||||
errUnsupportedMetadataKvVersion = "cannot perform metadata fetch operations with kv version v1"
|
||||
errNotFound = "secret not found"
|
||||
errIrsaTokenEnvVarNotFoundOnPod = "expected env variable: %s not found on controller's pod"
|
||||
errIrsaTokenFileNotFoundOnPod = "web ddentity token file not found at %s location: %w"
|
||||
errIrsaTokenFileNotReadable = "could not read the web identity token from the file %s: %w"
|
||||
errIrsaTokenNotValidJWT = "could not parse web identity token available at %s. not a valid jwt?: %w"
|
||||
errPodInfoNotFoundOnToken = "could not find pod identity info on token %s: %w"
|
||||
|
||||
errGetKubeSA = "cannot get Kubernetes service account %q: %w"
|
||||
errGetKubeSASecrets = "cannot find secrets bound to service account: %q"
|
||||
|
@ -352,6 +365,29 @@ func (c *Connector) ValidateStore(store esv1beta1.GenericStore) error {
|
|||
return fmt.Errorf(errInvalidTokenRef, err)
|
||||
}
|
||||
}
|
||||
if p.Auth.Iam != nil {
|
||||
if p.Auth.Iam.JWTAuth != nil {
|
||||
if p.Auth.Iam.JWTAuth.ServiceAccountRef != nil {
|
||||
if err := utils.ValidateReferentServiceAccountSelector(store, *p.Auth.Iam.JWTAuth.ServiceAccountRef); err != nil {
|
||||
return fmt.Errorf(errInvalidTokenRef, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.Auth.Iam.SecretRef != nil {
|
||||
if err := utils.ValidateReferentSecretSelector(store, p.Auth.Iam.SecretRef.AccessKeyID); err != nil {
|
||||
return fmt.Errorf(errInvalidTokenRef, err)
|
||||
}
|
||||
if err := utils.ValidateReferentSecretSelector(store, p.Auth.Iam.SecretRef.SecretAccessKey); err != nil {
|
||||
return fmt.Errorf(errInvalidTokenRef, err)
|
||||
}
|
||||
if p.Auth.Iam.SecretRef.SessionToken != nil {
|
||||
if err := utils.ValidateReferentSecretSelector(store, *p.Auth.Iam.SecretRef.SessionToken); err != nil {
|
||||
return fmt.Errorf(errInvalidTokenRef, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -740,6 +776,15 @@ func isReferentSpec(prov *esv1beta1.VaultProvider) bool {
|
|||
if prov.Auth.Cert != nil && prov.Auth.Cert.SecretRef.Namespace == nil {
|
||||
return true
|
||||
}
|
||||
if prov.Auth.Iam != nil && prov.Auth.Iam.JWTAuth != nil && prov.Auth.Iam.JWTAuth.ServiceAccountRef != nil && prov.Auth.Iam.JWTAuth.ServiceAccountRef.Namespace == nil {
|
||||
return true
|
||||
}
|
||||
if prov.Auth.Iam != nil && prov.Auth.Iam.SecretRef != nil &&
|
||||
(prov.Auth.Iam.SecretRef.AccessKeyID.Namespace == nil ||
|
||||
prov.Auth.Iam.SecretRef.SecretAccessKey.Namespace == nil ||
|
||||
(prov.Auth.Iam.SecretRef.SessionToken != nil && prov.Auth.Iam.SecretRef.SessionToken.Namespace == nil)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -1034,6 +1079,12 @@ func (v *client) setAuth(ctx context.Context, cfg *vault.Config) error {
|
|||
return err
|
||||
}
|
||||
|
||||
tokenExists, err = setIamAuthToken(ctx, v, vaultiamauth.DefaultJWTProvider, vaultiamauth.DefaultSTSProvider)
|
||||
if tokenExists {
|
||||
v.log.V(1).Info("Retrieved new token using IAM auth")
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.New(errAuthFormat)
|
||||
}
|
||||
|
||||
|
@ -1110,6 +1161,19 @@ func setCertAuthToken(ctx context.Context, v *client, cfg *vault.Config) (bool,
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func setIamAuthToken(ctx context.Context, v *client, jwtProvider util.JwtProviderFactory, assumeRoler vaultiamauth.STSProvider) (bool, error) {
|
||||
iamAuth := v.store.Auth.Iam
|
||||
isClusterKind := v.storeKind == esv1beta1.ClusterSecretStoreKind
|
||||
if iamAuth != nil {
|
||||
err := v.requestTokenWithIamAuth(ctx, iamAuth, isClusterKind, v.kube, v.namespace, jwtProvider, assumeRoler)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (v *client) secretKeyRefForServiceAccount(ctx context.Context, serviceAccountRef *esmeta.ServiceAccountSelector) (string, error) {
|
||||
serviceAccount := &corev1.ServiceAccount{}
|
||||
ref := types.NamespacedName{
|
||||
|
@ -1407,6 +1471,133 @@ func (v *client) requestTokenWithCertAuth(ctx context.Context, certAuth *esv1bet
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *client) requestTokenWithIamAuth(ctx context.Context, iamAuth *esv1beta1.VaultIamAuth, ick bool, k kclient.Client, n string, jwtProvider util.JwtProviderFactory, assumeRoler vaultiamauth.STSProvider) error {
|
||||
jwtAuth := iamAuth.JWTAuth
|
||||
secretRefAuth := iamAuth.SecretRef
|
||||
regionAWS := defaultAWSRegion
|
||||
awsAuthMountPath := defaultAWSAuthMountPath
|
||||
if iamAuth.Region != "" {
|
||||
regionAWS = iamAuth.Region
|
||||
}
|
||||
if iamAuth.Path != "" {
|
||||
awsAuthMountPath = iamAuth.Path
|
||||
}
|
||||
var creds *credentials.Credentials
|
||||
var err error
|
||||
if jwtAuth != nil { // use credentials from a sa explicitly defined and referenced. Highest preference is given to this method/configuration.
|
||||
creds, err = vaultiamauth.CredsFromServiceAccount(ctx, *iamAuth, regionAWS, ick, k, n, jwtProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if secretRefAuth != nil { // if jwtAuth is not defined, check if secretRef is defined. Second preference.
|
||||
logger.V(1).Info("using credentials from secretRef")
|
||||
creds, err = vaultiamauth.CredsFromSecretRef(ctx, *iamAuth, ick, k, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Neither of jwtAuth or secretRefAuth defined. Last preference.
|
||||
// Default to controller pod's identity
|
||||
if jwtAuth == nil && secretRefAuth == nil {
|
||||
// Checking if controller pod's service account is IRSA enabled and Web Identity token is available on pod
|
||||
tknFile, tknFileEnvVarPresent := os.LookupEnv(vaultiamauth.AWSWebIdentityTokenFileEnvVar)
|
||||
if !tknFileEnvVarPresent {
|
||||
return fmt.Errorf(errIrsaTokenEnvVarNotFoundOnPod, vaultiamauth.AWSWebIdentityTokenFileEnvVar) // No Web Identity(IRSA) token found on pod
|
||||
}
|
||||
|
||||
// IRSA enabled service account, let's check that the jwt token filemount and file exists
|
||||
if _, err := os.Stat(tknFile); err != nil {
|
||||
return fmt.Errorf(errIrsaTokenFileNotFoundOnPod, tknFile, err)
|
||||
}
|
||||
|
||||
// everything looks good so far, let's fetch the jwt token from AWS_WEB_IDENTITY_TOKEN_FILE
|
||||
jwtByte, err := os.ReadFile(tknFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf(errIrsaTokenFileNotReadable, tknFile, err)
|
||||
}
|
||||
|
||||
// let's parse the jwt token
|
||||
parser := jwt.NewParser(jwt.WithoutClaimsValidation())
|
||||
|
||||
token, _, err := parser.ParseUnverified(string(jwtByte), jwt.MapClaims{})
|
||||
if err != nil {
|
||||
return fmt.Errorf(errIrsaTokenNotValidJWT, tknFile, err) // JWT token parser error
|
||||
}
|
||||
|
||||
var ns string
|
||||
var sa string
|
||||
|
||||
// let's fetch the namespace and serviceaccount from parsed jwt token
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok {
|
||||
ns = claims["kubernetes.io"].(map[string]interface{})["namespace"].(string)
|
||||
sa = claims["kubernetes.io"].(map[string]interface{})["serviceaccount"].(map[string]interface{})["name"].(string)
|
||||
} else {
|
||||
return fmt.Errorf(errPodInfoNotFoundOnToken, tknFile, err)
|
||||
}
|
||||
|
||||
creds, err = vaultiamauth.CredsFromControllerServiceAccount(ctx, sa, ns, regionAWS, k, jwtProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
config := aws.NewConfig().WithEndpointResolver(vaultiamauth.ResolveEndpoint())
|
||||
if creds != nil {
|
||||
config.WithCredentials(creds)
|
||||
}
|
||||
|
||||
if regionAWS != "" {
|
||||
config.WithRegion(regionAWS)
|
||||
}
|
||||
|
||||
sess, err := vaultiamauth.GetAWSSession(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if iamAuth.AWSIAMRole != "" {
|
||||
stsclient := assumeRoler(sess)
|
||||
if iamAuth.ExternalID != "" {
|
||||
var setExternalID = func(p *stscreds.AssumeRoleProvider) {
|
||||
p.ExternalID = aws.String(iamAuth.ExternalID)
|
||||
}
|
||||
sess.Config.WithCredentials(stscreds.NewCredentialsWithClient(stsclient, iamAuth.AWSIAMRole, setExternalID))
|
||||
} else {
|
||||
sess.Config.WithCredentials(stscreds.NewCredentialsWithClient(stsclient, iamAuth.AWSIAMRole))
|
||||
}
|
||||
}
|
||||
|
||||
getCreds, err := sess.Config.Credentials.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Set environment variables. These would be fetched by Login
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", getCreds.AccessKeyID)
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", getCreds.SecretAccessKey)
|
||||
os.Setenv("AWS_SESSION_TOKEN", getCreds.SessionToken)
|
||||
|
||||
var awsAuthClient *authaws.AWSAuth
|
||||
|
||||
if iamAuth.VaultAWSIAMServerID != "" {
|
||||
awsAuthClient, err = authaws.NewAWSAuth(authaws.WithRegion(regionAWS), authaws.WithIAMAuth(), authaws.WithRole(iamAuth.Role), authaws.WithMountPath(awsAuthMountPath), authaws.WithIAMServerIDHeader(iamAuth.VaultAWSIAMServerID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
awsAuthClient, err = authaws.NewAWSAuth(authaws.WithRegion(regionAWS), authaws.WithIAMAuth(), authaws.WithRole(iamAuth.Role), authaws.WithMountPath(awsAuthMountPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = v.auth.Login(ctx, awsAuthClient)
|
||||
metrics.ObserveAPICall(metrics.ProviderHCVault, metrics.CallHCVaultLogin, err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
var vaultTokenCacheSize int
|
||||
fs := pflag.NewFlagSet("vault", pflag.ExitOnError)
|
||||
|
|
|
@ -161,6 +161,45 @@ func makeInvalidClusterSecretStoreWithK8sCerts() *esv1beta1.ClusterSecretStore {
|
|||
}
|
||||
}
|
||||
|
||||
func makeValidSecretStoreWithIamAuthSecret() *esv1beta1.SecretStore {
|
||||
return &esv1beta1.SecretStore{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vault-store",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: esv1beta1.SecretStoreSpec{
|
||||
Provider: &esv1beta1.SecretStoreProvider{
|
||||
Vault: &esv1beta1.VaultProvider{
|
||||
Server: "https://vault.example.com:8200",
|
||||
Path: &secretStorePath,
|
||||
Version: esv1beta1.VaultKVStoreV2,
|
||||
Auth: esv1beta1.VaultAuth{
|
||||
Iam: &esv1beta1.VaultIamAuth{
|
||||
Path: "aws",
|
||||
Region: "us-east-1",
|
||||
Role: "vault-role",
|
||||
SecretRef: &esv1beta1.VaultAwsAuthSecretRef{
|
||||
AccessKeyID: esmeta.SecretKeySelector{
|
||||
Name: "vault-iam-creds-secret",
|
||||
Key: "access-key",
|
||||
},
|
||||
SecretAccessKey: esmeta.SecretKeySelector{
|
||||
Name: "vault-iam-creds-secret",
|
||||
Key: "secret-access-key",
|
||||
},
|
||||
SessionToken: &esmeta.SecretKeySelector{
|
||||
Name: "vault-iam-creds-secret",
|
||||
Key: "secret-session-token",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type secretStoreTweakFn func(s *esv1beta1.SecretStore)
|
||||
|
||||
func makeSecretStore(tweaks ...secretStoreTweakFn) *esv1beta1.SecretStore {
|
||||
|
@ -335,6 +374,29 @@ MIIFkTCCA3mgAwIBAgIUBEUg3m/WqAsWHG4Q/II3IePFfuowDQYJKoZIhvcNAQELBQAwWDELMAkGA1UE
|
|||
err: fmt.Errorf(errVaultCert, errors.New(`cannot find secret data for key: "cert"`)),
|
||||
},
|
||||
},
|
||||
"SuccessfulVaultStoreWithIamAuthSecret": {
|
||||
reason: "Should return a Vault provider successfully",
|
||||
args: args{
|
||||
store: makeValidSecretStoreWithIamAuthSecret(),
|
||||
ns: "default",
|
||||
kube: clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vault-iam-creds-secret",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"access-key": []byte("TESTING"),
|
||||
"secret-access-key": []byte("ABCDEF"),
|
||||
"secret-session-token": []byte("c2VjcmV0LXNlc3Npb24tdG9rZW4K"),
|
||||
},
|
||||
}).Build(),
|
||||
corev1: utilfake.NewCreateTokenMock().WithToken("ok"),
|
||||
newClientFunc: fake.ClientWithLoginMock,
|
||||
},
|
||||
want: want{
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
"SuccessfulVaultStoreWithK8sCertConfigMap": {
|
||||
reason: "Should return a Vault prodvider with the cert from k8s",
|
||||
args: args{
|
||||
|
|
Loading…
Reference in a new issue