Browse Source

feat(vault): add option for JWT backend to authenticate with Kubernetes service account token (#768)

Alfred Krohmer 4 years ago
parent
commit
d7022b1bef

+ 31 - 4
apis/externalsecrets/v1alpha1/secretstore_vault_types.go

@@ -203,8 +203,29 @@ type VaultLdapAuth struct {
 	SecretRef esmeta.SecretKeySelector `json:"secretRef,omitempty"`
 }
 
+// VaultKubernetesServiceAccountTokenAuth authenticates with Vault using a temporary
+// Kubernetes service account token retrieved by the `TokenRequest` API.
+type VaultKubernetesServiceAccountTokenAuth struct {
+	// Service account field containing the name of a kubernetes ServiceAccount.
+	ServiceAccountRef esmeta.ServiceAccountSelector `json:"serviceAccountRef"`
+
+	// Optional audiences field that will be used to request a temporary Kubernetes service
+	// account token for the service account referenced by `serviceAccountRef`.
+	// Defaults to a single audience `vault` it not specified.
+	// +optional
+	Audiences *[]string `json:"audiences,omitempty"`
+
+	// Optional expiration time in seconds that will be used to request a temporary
+	// Kubernetes service account token for the service account referenced by
+	// `serviceAccountRef`.
+	// Defaults to 10 minutes.
+	// +optional
+	ExpirationSeconds *int64 `json:"expirationSeconds,omitempty"`
+}
+
 // VaultJwtAuth authenticates with Vault using the JWT/OIDC authentication
-// method, with the role name and token stored in a Kubernetes Secret resource.
+// method, with the role name and a token stored in a Kubernetes Secret resource or
+// a Kubernetes service account token retrieved via `TokenRequest`.
 type VaultJwtAuth struct {
 	// Path where the JWT authentication backend is mounted
 	// in Vault, e.g: "jwt"
@@ -216,9 +237,15 @@ type VaultJwtAuth struct {
 	// +optional
 	Role string `json:"role"`
 
-	// SecretRef to a key in a Secret resource containing JWT token to
-	// authenticate with Vault using the JWT/OIDC authentication method
-	SecretRef esmeta.SecretKeySelector `json:"secretRef,omitempty"`
+	// Optional SecretRef that refers to a key in a Secret resource containing JWT token to
+	// authenticate with Vault using the JWT/OIDC authentication method.
+	// +optional
+	SecretRef *esmeta.SecretKeySelector `json:"secretRef,omitempty"`
+
+	// Optional ServiceAccountToken specifies the Kubernetes service account for which to request
+	// a token for with the `TokenRequest` API.
+	// +optional
+	KubernetesServiceAccountToken *VaultKubernetesServiceAccountTokenAuth `json:"kubernetesServiceAccountToken,omitempty"`
 }
 
 // VaultJwtAuth authenticates with Vault using the JWT/OIDC authentication

+ 40 - 1
apis/externalsecrets/v1alpha1/zz_generated.deepcopy.go

@@ -1379,7 +1379,16 @@ func (in *VaultCertAuth) DeepCopy() *VaultCertAuth {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *VaultJwtAuth) DeepCopyInto(out *VaultJwtAuth) {
 	*out = *in
-	in.SecretRef.DeepCopyInto(&out.SecretRef)
+	if in.SecretRef != nil {
+		in, out := &in.SecretRef, &out.SecretRef
+		*out = new(metav1.SecretKeySelector)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.KubernetesServiceAccountToken != nil {
+		in, out := &in.KubernetesServiceAccountToken, &out.KubernetesServiceAccountToken
+		*out = new(VaultKubernetesServiceAccountTokenAuth)
+		(*in).DeepCopyInto(*out)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultJwtAuth.
@@ -1418,6 +1427,36 @@ func (in *VaultKubernetesAuth) DeepCopy() *VaultKubernetesAuth {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VaultKubernetesServiceAccountTokenAuth) DeepCopyInto(out *VaultKubernetesServiceAccountTokenAuth) {
+	*out = *in
+	in.ServiceAccountRef.DeepCopyInto(&out.ServiceAccountRef)
+	if in.Audiences != nil {
+		in, out := &in.Audiences, &out.Audiences
+		*out = new([]string)
+		if **in != nil {
+			in, out := *in, *out
+			*out = make([]string, len(*in))
+			copy(*out, *in)
+		}
+	}
+	if in.ExpirationSeconds != nil {
+		in, out := &in.ExpirationSeconds, &out.ExpirationSeconds
+		*out = new(int64)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultKubernetesServiceAccountTokenAuth.
+func (in *VaultKubernetesServiceAccountTokenAuth) DeepCopy() *VaultKubernetesServiceAccountTokenAuth {
+	if in == nil {
+		return nil
+	}
+	out := new(VaultKubernetesServiceAccountTokenAuth)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *VaultLdapAuth) DeepCopyInto(out *VaultLdapAuth) {
 	*out = *in
 	in.SecretRef.DeepCopyInto(&out.SecretRef)

+ 31 - 4
apis/externalsecrets/v1beta1/secretstore_vault_types.go

@@ -203,8 +203,29 @@ type VaultLdapAuth struct {
 	SecretRef esmeta.SecretKeySelector `json:"secretRef,omitempty"`
 }
 
+// VaultKubernetesServiceAccountTokenAuth authenticates with Vault using a temporary
+// Kubernetes service account token retrieved by the `TokenRequest` API.
+type VaultKubernetesServiceAccountTokenAuth struct {
+	// Service account field containing the name of a kubernetes ServiceAccount.
+	ServiceAccountRef esmeta.ServiceAccountSelector `json:"serviceAccountRef"`
+
+	// Optional audiences field that will be used to request a temporary Kubernetes service
+	// account token for the service account referenced by `serviceAccountRef`.
+	// Defaults to a single audience `vault` it not specified.
+	// +optional
+	Audiences *[]string `json:"audiences,omitempty"`
+
+	// Optional expiration time in seconds that will be used to request a temporary
+	// Kubernetes service account token for the service account referenced by
+	// `serviceAccountRef`.
+	// Defaults to 10 minutes.
+	// +optional
+	ExpirationSeconds *int64 `json:"expirationSeconds,omitempty"`
+}
+
 // VaultJwtAuth authenticates with Vault using the JWT/OIDC authentication
-// method, with the role name and token stored in a Kubernetes Secret resource.
+// method, with the role name and a token stored in a Kubernetes Secret resource or
+// a Kubernetes service account token retrieved via `TokenRequest`.
 type VaultJwtAuth struct {
 	// Path where the JWT authentication backend is mounted
 	// in Vault, e.g: "jwt"
@@ -216,9 +237,15 @@ type VaultJwtAuth struct {
 	// +optional
 	Role string `json:"role"`
 
-	// SecretRef to a key in a Secret resource containing JWT token to
-	// authenticate with Vault using the JWT/OIDC authentication method
-	SecretRef esmeta.SecretKeySelector `json:"secretRef,omitempty"`
+	// Optional SecretRef that refers to a key in a Secret resource containing JWT token to
+	// authenticate with Vault using the JWT/OIDC authentication method.
+	// +optional
+	SecretRef *esmeta.SecretKeySelector `json:"secretRef,omitempty"`
+
+	// Optional ServiceAccountToken specifies the Kubernetes service account for which to request
+	// a token for with the `TokenRequest` API.
+	// +optional
+	KubernetesServiceAccountToken *VaultKubernetesServiceAccountTokenAuth `json:"kubernetesServiceAccountToken,omitempty"`
 }
 
 // VaultJwtAuth authenticates with Vault using the JWT/OIDC authentication

+ 40 - 1
apis/externalsecrets/v1beta1/zz_generated.deepcopy.go

@@ -1609,7 +1609,16 @@ func (in *VaultCertAuth) DeepCopy() *VaultCertAuth {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *VaultJwtAuth) DeepCopyInto(out *VaultJwtAuth) {
 	*out = *in
-	in.SecretRef.DeepCopyInto(&out.SecretRef)
+	if in.SecretRef != nil {
+		in, out := &in.SecretRef, &out.SecretRef
+		*out = new(metav1.SecretKeySelector)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.KubernetesServiceAccountToken != nil {
+		in, out := &in.KubernetesServiceAccountToken, &out.KubernetesServiceAccountToken
+		*out = new(VaultKubernetesServiceAccountTokenAuth)
+		(*in).DeepCopyInto(*out)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultJwtAuth.
@@ -1648,6 +1657,36 @@ func (in *VaultKubernetesAuth) DeepCopy() *VaultKubernetesAuth {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VaultKubernetesServiceAccountTokenAuth) DeepCopyInto(out *VaultKubernetesServiceAccountTokenAuth) {
+	*out = *in
+	in.ServiceAccountRef.DeepCopyInto(&out.ServiceAccountRef)
+	if in.Audiences != nil {
+		in, out := &in.Audiences, &out.Audiences
+		*out = new([]string)
+		if **in != nil {
+			in, out := *in, *out
+			*out = make([]string, len(*in))
+			copy(*out, *in)
+		}
+	}
+	if in.ExpirationSeconds != nil {
+		in, out := &in.ExpirationSeconds, &out.ExpirationSeconds
+		*out = new(int64)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultKubernetesServiceAccountTokenAuth.
+func (in *VaultKubernetesServiceAccountTokenAuth) DeepCopy() *VaultKubernetesServiceAccountTokenAuth {
+	if in == nil {
+		return nil
+	}
+	out := new(VaultKubernetesServiceAccountTokenAuth)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *VaultLdapAuth) DeepCopyInto(out *VaultLdapAuth) {
 	*out = *in
 	in.SecretRef.DeepCopyInto(&out.SecretRef)

+ 90 - 6
config/crds/bases/external-secrets.io_clustersecretstores.yaml

@@ -908,6 +908,48 @@ spec:
                             description: Jwt authenticates with Vault by passing role
                               and JWT token using the JWT/OIDC authentication method
                             properties:
+                              kubernetesServiceAccountToken:
+                                description: Optional ServiceAccountToken specifies
+                                  the Kubernetes service account for which to request
+                                  a token for with the `TokenRequest` API.
+                                properties:
+                                  audiences:
+                                    description: Optional audiences field that will
+                                      be used to request a temporary Kubernetes service
+                                      account token for the service account referenced
+                                      by `serviceAccountRef`. Defaults to a single
+                                      audience `vault` it not specified.
+                                    items:
+                                      type: string
+                                    type: array
+                                  expirationSeconds:
+                                    description: Optional expiration time in seconds
+                                      that will be used to request a temporary Kubernetes
+                                      service account token for the service account
+                                      referenced by `serviceAccountRef`. Defaults
+                                      to 10 minutes.
+                                    format: int64
+                                    type: integer
+                                  serviceAccountRef:
+                                    description: Service account field containing
+                                      the name of a kubernetes ServiceAccount.
+                                    properties:
+                                      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
+                                required:
+                                - serviceAccountRef
+                                type: object
                               path:
                                 default: jwt
                                 description: 'Path where the JWT authentication backend
@@ -918,9 +960,9 @@ spec:
                                   the JWT/OIDC Vault authentication method
                                 type: string
                               secretRef:
-                                description: SecretRef to a key in a Secret resource
-                                  containing JWT token to authenticate with Vault
-                                  using the JWT/OIDC authentication method
+                                description: Optional SecretRef that refers to a key
+                                  in a Secret resource containing JWT token to authenticate
+                                  with Vault using the JWT/OIDC authentication method.
                                 properties:
                                   key:
                                     description: The key of the entry in the Secret
@@ -2227,6 +2269,48 @@ spec:
                             description: Jwt authenticates with Vault by passing role
                               and JWT token using the JWT/OIDC authentication method
                             properties:
+                              kubernetesServiceAccountToken:
+                                description: Optional ServiceAccountToken specifies
+                                  the Kubernetes service account for which to request
+                                  a token for with the `TokenRequest` API.
+                                properties:
+                                  audiences:
+                                    description: Optional audiences field that will
+                                      be used to request a temporary Kubernetes service
+                                      account token for the service account referenced
+                                      by `serviceAccountRef`. Defaults to a single
+                                      audience `vault` it not specified.
+                                    items:
+                                      type: string
+                                    type: array
+                                  expirationSeconds:
+                                    description: Optional expiration time in seconds
+                                      that will be used to request a temporary Kubernetes
+                                      service account token for the service account
+                                      referenced by `serviceAccountRef`. Defaults
+                                      to 10 minutes.
+                                    format: int64
+                                    type: integer
+                                  serviceAccountRef:
+                                    description: Service account field containing
+                                      the name of a kubernetes ServiceAccount.
+                                    properties:
+                                      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
+                                required:
+                                - serviceAccountRef
+                                type: object
                               path:
                                 default: jwt
                                 description: 'Path where the JWT authentication backend
@@ -2237,9 +2321,9 @@ spec:
                                   the JWT/OIDC Vault authentication method
                                 type: string
                               secretRef:
-                                description: SecretRef to a key in a Secret resource
-                                  containing JWT token to authenticate with Vault
-                                  using the JWT/OIDC authentication method
+                                description: Optional SecretRef that refers to a key
+                                  in a Secret resource containing JWT token to authenticate
+                                  with Vault using the JWT/OIDC authentication method.
                                 properties:
                                   key:
                                     description: The key of the entry in the Secret

+ 90 - 6
config/crds/bases/external-secrets.io_secretstores.yaml

@@ -908,6 +908,48 @@ spec:
                             description: Jwt authenticates with Vault by passing role
                               and JWT token using the JWT/OIDC authentication method
                             properties:
+                              kubernetesServiceAccountToken:
+                                description: Optional ServiceAccountToken specifies
+                                  the Kubernetes service account for which to request
+                                  a token for with the `TokenRequest` API.
+                                properties:
+                                  audiences:
+                                    description: Optional audiences field that will
+                                      be used to request a temporary Kubernetes service
+                                      account token for the service account referenced
+                                      by `serviceAccountRef`. Defaults to a single
+                                      audience `vault` it not specified.
+                                    items:
+                                      type: string
+                                    type: array
+                                  expirationSeconds:
+                                    description: Optional expiration time in seconds
+                                      that will be used to request a temporary Kubernetes
+                                      service account token for the service account
+                                      referenced by `serviceAccountRef`. Defaults
+                                      to 10 minutes.
+                                    format: int64
+                                    type: integer
+                                  serviceAccountRef:
+                                    description: Service account field containing
+                                      the name of a kubernetes ServiceAccount.
+                                    properties:
+                                      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
+                                required:
+                                - serviceAccountRef
+                                type: object
                               path:
                                 default: jwt
                                 description: 'Path where the JWT authentication backend
@@ -918,9 +960,9 @@ spec:
                                   the JWT/OIDC Vault authentication method
                                 type: string
                               secretRef:
-                                description: SecretRef to a key in a Secret resource
-                                  containing JWT token to authenticate with Vault
-                                  using the JWT/OIDC authentication method
+                                description: Optional SecretRef that refers to a key
+                                  in a Secret resource containing JWT token to authenticate
+                                  with Vault using the JWT/OIDC authentication method.
                                 properties:
                                   key:
                                     description: The key of the entry in the Secret
@@ -2230,6 +2272,48 @@ spec:
                             description: Jwt authenticates with Vault by passing role
                               and JWT token using the JWT/OIDC authentication method
                             properties:
+                              kubernetesServiceAccountToken:
+                                description: Optional ServiceAccountToken specifies
+                                  the Kubernetes service account for which to request
+                                  a token for with the `TokenRequest` API.
+                                properties:
+                                  audiences:
+                                    description: Optional audiences field that will
+                                      be used to request a temporary Kubernetes service
+                                      account token for the service account referenced
+                                      by `serviceAccountRef`. Defaults to a single
+                                      audience `vault` it not specified.
+                                    items:
+                                      type: string
+                                    type: array
+                                  expirationSeconds:
+                                    description: Optional expiration time in seconds
+                                      that will be used to request a temporary Kubernetes
+                                      service account token for the service account
+                                      referenced by `serviceAccountRef`. Defaults
+                                      to 10 minutes.
+                                    format: int64
+                                    type: integer
+                                  serviceAccountRef:
+                                    description: Service account field containing
+                                      the name of a kubernetes ServiceAccount.
+                                    properties:
+                                      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
+                                required:
+                                - serviceAccountRef
+                                type: object
                               path:
                                 default: jwt
                                 description: 'Path where the JWT authentication backend
@@ -2240,9 +2324,9 @@ spec:
                                   the JWT/OIDC Vault authentication method
                                 type: string
                               secretRef:
-                                description: SecretRef to a key in a Secret resource
-                                  containing JWT token to authenticate with Vault
-                                  using the JWT/OIDC authentication method
+                                description: Optional SecretRef that refers to a key
+                                  in a Secret resource containing JWT token to authenticate
+                                  with Vault using the JWT/OIDC authentication method.
                                 properties:
                                   key:
                                     description: The key of the entry in the Secret

+ 112 - 4
deploy/crds/bundle.yaml

@@ -999,6 +999,33 @@ spec:
                             jwt:
                               description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method
                               properties:
+                                kubernetesServiceAccountToken:
+                                  description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API.
+                                  properties:
+                                    audiences:
+                                      description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified.
+                                      items:
+                                        type: string
+                                      type: array
+                                    expirationSeconds:
+                                      description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes.
+                                      format: int64
+                                      type: integer
+                                    serviceAccountRef:
+                                      description: Service account field containing the name of a kubernetes ServiceAccount.
+                                      properties:
+                                        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
+                                  required:
+                                    - serviceAccountRef
+                                  type: object
                                 path:
                                   default: jwt
                                   description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"'
@@ -1007,7 +1034,7 @@ spec:
                                   description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method
                                   type: string
                                 secretRef:
-                                  description: SecretRef to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method
+                                  description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method.
                                   properties:
                                     key:
                                       description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required.
@@ -1972,6 +1999,33 @@ spec:
                             jwt:
                               description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method
                               properties:
+                                kubernetesServiceAccountToken:
+                                  description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API.
+                                  properties:
+                                    audiences:
+                                      description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified.
+                                      items:
+                                        type: string
+                                      type: array
+                                    expirationSeconds:
+                                      description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes.
+                                      format: int64
+                                      type: integer
+                                    serviceAccountRef:
+                                      description: Service account field containing the name of a kubernetes ServiceAccount.
+                                      properties:
+                                        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
+                                  required:
+                                    - serviceAccountRef
+                                  type: object
                                 path:
                                   default: jwt
                                   description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"'
@@ -1980,7 +2034,7 @@ spec:
                                   description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method
                                   type: string
                                 secretRef:
-                                  description: SecretRef to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method
+                                  description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method.
                                   properties:
                                     key:
                                       description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required.
@@ -3487,6 +3541,33 @@ spec:
                             jwt:
                               description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method
                               properties:
+                                kubernetesServiceAccountToken:
+                                  description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API.
+                                  properties:
+                                    audiences:
+                                      description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified.
+                                      items:
+                                        type: string
+                                      type: array
+                                    expirationSeconds:
+                                      description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes.
+                                      format: int64
+                                      type: integer
+                                    serviceAccountRef:
+                                      description: Service account field containing the name of a kubernetes ServiceAccount.
+                                      properties:
+                                        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
+                                  required:
+                                    - serviceAccountRef
+                                  type: object
                                 path:
                                   default: jwt
                                   description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"'
@@ -3495,7 +3576,7 @@ spec:
                                   description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method
                                   type: string
                                 secretRef:
-                                  description: SecretRef to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method
+                                  description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method.
                                   properties:
                                     key:
                                       description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required.
@@ -4463,6 +4544,33 @@ spec:
                             jwt:
                               description: Jwt authenticates with Vault by passing role and JWT token using the JWT/OIDC authentication method
                               properties:
+                                kubernetesServiceAccountToken:
+                                  description: Optional ServiceAccountToken specifies the Kubernetes service account for which to request a token for with the `TokenRequest` API.
+                                  properties:
+                                    audiences:
+                                      description: Optional audiences field that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to a single audience `vault` it not specified.
+                                      items:
+                                        type: string
+                                      type: array
+                                    expirationSeconds:
+                                      description: Optional expiration time in seconds that will be used to request a temporary Kubernetes service account token for the service account referenced by `serviceAccountRef`. Defaults to 10 minutes.
+                                      format: int64
+                                      type: integer
+                                    serviceAccountRef:
+                                      description: Service account field containing the name of a kubernetes ServiceAccount.
+                                      properties:
+                                        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
+                                  required:
+                                    - serviceAccountRef
+                                  type: object
                                 path:
                                   default: jwt
                                   description: 'Path where the JWT authentication backend is mounted in Vault, e.g: "jwt"'
@@ -4471,7 +4579,7 @@ spec:
                                   description: Role is a JWT role to authenticate using the JWT/OIDC Vault authentication method
                                   type: string
                                 secretRef:
-                                  description: SecretRef to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method
+                                  description: Optional SecretRef that refers to a key in a Secret resource containing JWT token to authenticate with Vault using the JWT/OIDC authentication method.
                                   properties:
                                     key:
                                       description: The key of the entry in the Secret resource's `data` field to be used. Some instances of this field may be defaulted, in others it may be required.

+ 2 - 2
docs/provider-hashicorp-vault.md

@@ -295,9 +295,9 @@ in a `Kind=Secret` referenced by the `secretRef`.
 
 #### JWT/OIDC authentication
 
-[JWT/OIDC](https://www.vaultproject.io/docs/auth/jwt) uses a
+[JWT/OIDC](https://www.vaultproject.io/docs/auth/jwt) uses either a
 [JWT](https://jwt.io/) token stored in a `Kind=Secret` and referenced by the
-`secretRef`. Optionally a `role` field can be defined in a `Kind=SecretStore`
+`secretRef` or a temporary Kubernetes service account token retrieved via the `TokenRequest` API. Optionally a `role` field can be defined in a `Kind=SecretStore`
 or `Kind=ClusterSecretStore` resource.
 
 ```yaml

+ 12 - 0
docs/snippets/vault-jwt-store.yaml

@@ -17,6 +17,18 @@ spec:
           path: "jwt"
           # JWT role configured in a Vault server, optional.
           role: "vault-jwt-role"
+
+          # Retrieve JWT token from a Kubernetes secret
           secretRef:
             name: "my-secret"
             key: "jwt-token"
+
+          # ... or retrieve a Kubernetes service account token via the `TokenRequest` API
+          kubernetesServiceAccountToken:
+            serviceAccountRef:
+              name: "my-sa"
+            # `audiences` defaults to `["vault"]` it not supplied
+            audiences:
+            - vault
+            # `expirationSeconds` defaults to 10 minutes if not supplied
+            expirationSeconds: 600

+ 2 - 0
e2e/framework/addon/vault.go

@@ -58,6 +58,7 @@ type Vault struct {
 	JWTToken           string
 	JWTRole            string
 	JWTPath            string
+	JWTK8sPath         string
 	KubernetesAuthPath string
 	KubernetesAuthRole string
 
@@ -162,6 +163,7 @@ func (l *Vault) initVault() error {
 	l.JWTPubkey = jwtPubkey
 	l.JWTToken = jwtToken
 	l.JWTPath = "myjwt"                                // see configure-vault.sh
+	l.JWTK8sPath = "myjwtk8s"                          // see configure-vault.sh
 	l.JWTRole = "external-secrets-operator"            // see configure-vault.sh
 	l.KubernetesAuthPath = "mykubernetes"              // see configure-vault.sh
 	l.KubernetesAuthRole = "external-secrets-operator" // see configure-vault.sh

+ 15 - 0
e2e/k8s/vault-config/configure-vault.sh

@@ -69,6 +69,21 @@ vault write auth/myjwt/role/external-secrets-operator \
     policies=external-secrets-operator \
     ttl=1h
 
+vault auth enable -path=myjwtk8s jwt
+
+vault write auth/myjwtk8s/config \
+   oidc_discovery_url=https://kubernetes.default.svc.cluster.local \
+   oidc_discovery_ca_pem=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
+   bound_issuer="https://kubernetes.default.svc.cluster.local" \
+   default_role="external-secrets-operator"
+
+vault write auth/myjwtk8s/role/external-secrets-operator \
+    role_type="jwt" \
+    bound_audiences="vault.client" \
+    user_claim="sub" \
+    policies=external-secrets-operator \
+    ttl=1h
+
 # ------------------
 #   Kubernetes AUTH
 #   https://www.vaultproject.io/docs/auth/kubernetes

+ 0 - 9
e2e/kind.yaml

@@ -1,14 +1,5 @@
 kind: Cluster
 apiVersion: kind.x-k8s.io/v1alpha4
-kubeadmConfigPatches:
-- |
-  kind: ClusterConfiguration
-  apiServer:
-    extraArgs:
-      api-audiences: "sts.amazonaws.com"
-      service-account-key-file: "/etc/kubernetes/pki/sa.pub"
-      service-account-signing-key-file: "/etc/kubernetes/pki/sa.key"
-      service-account-issuer: "https://s3-XXXXXXXXXX.amazonaws.com/XXXXXXXXXXXXXXXXXXXXX"
 nodes:
 - role: control-plane
 - role: worker

+ 5 - 0
e2e/run.sh

@@ -34,6 +34,11 @@ kubectl create clusterrolebinding permissive-binding \
   --user=kubelet \
   --serviceaccount=default:external-secrets-e2e || true
 
+echo -e "Granting anonymous access to service account issuer discovery"
+kubectl create clusterrolebinding service-account-issuer-discovery-binding \
+  --clusterrole=system:service-account-issuer-discovery \
+  --group=system:unauthenticated || true
+
 echo -e "Waiting service account..."; \
 until kubectl get secret | grep -q -e ^external-secrets-e2e-token; do \
   echo -e "waiting for api token"; \

+ 23 - 1
e2e/suite/vault/provider.go

@@ -45,6 +45,7 @@ const (
 	appRoleAuthProviderName = "app-role-provider"
 	kvv1ProviderName        = "kv-v1-provider"
 	jwtProviderName         = "jwt-provider"
+	jwtK8sProviderName      = "jwt-k8s-provider"
 	kubernetesProviderName  = "kubernetes-provider"
 )
 
@@ -95,6 +96,7 @@ func (s *vaultProvider) BeforeEach() {
 	s.CreateAppRoleStore(v, ns)
 	s.CreateV1Store(v, ns)
 	s.CreateJWTStore(v, ns)
+	s.CreateJWTK8sStore(v, ns)
 	s.CreateKubernetesAuthStore(v, ns)
 }
 
@@ -249,7 +251,7 @@ func (s vaultProvider) CreateJWTStore(v *addon.Vault, ns string) {
 		Jwt: &esv1beta1.VaultJwtAuth{
 			Path: v.JWTPath,
 			Role: v.JWTRole,
-			SecretRef: esmeta.SecretKeySelector{
+			SecretRef: &esmeta.SecretKeySelector{
 				Name: "jwt-provider",
 				Key:  "jwt",
 			},
@@ -259,6 +261,26 @@ func (s vaultProvider) CreateJWTStore(v *addon.Vault, ns string) {
 	Expect(err).ToNot(HaveOccurred())
 }
 
+func (s vaultProvider) CreateJWTK8sStore(v *addon.Vault, ns string) {
+	secretStore := makeStore(jwtK8sProviderName, ns, v)
+	secretStore.Spec.Provider.Vault.Auth = esv1beta1.VaultAuth{
+		Jwt: &esv1beta1.VaultJwtAuth{
+			Path: v.JWTK8sPath,
+			Role: v.JWTRole,
+			KubernetesServiceAccountToken: &esv1beta1.VaultKubernetesServiceAccountTokenAuth{
+				ServiceAccountRef: esmeta.ServiceAccountSelector{
+					Name: "default",
+				},
+				Audiences: &[]string{
+					"vault.client",
+				},
+			},
+		},
+	}
+	err := s.framework.CRClient.Create(context.Background(), secretStore)
+	Expect(err).ToNot(HaveOccurred())
+}
+
 func (s vaultProvider) CreateKubernetesAuthStore(v *addon.Vault, ns string) {
 	secretStore := makeStore(kubernetesProviderName, ns, v)
 	secretStore.Spec.Provider.Vault.Auth = esv1beta1.VaultAuth{

+ 11 - 0
e2e/suite/vault/vault.go

@@ -30,6 +30,7 @@ const (
 	withApprole   = "with approle auth"
 	withV1        = "with v1 provider"
 	withJWT       = "with jwt provider"
+	withJWTK8s    = "with jwt k8s provider"
 	withK8s       = "with kubernetes provider"
 )
 
@@ -74,6 +75,12 @@ var _ = Describe("[vault]", Label("vault"), func() {
 		framework.Compose(withJWT, f, common.JSONDataWithTemplate, useJWTProvider),
 		framework.Compose(withJWT, f, common.DataPropertyDockerconfigJSON, useJWTProvider),
 		framework.Compose(withJWT, f, common.JSONDataWithoutTargetName, useJWTProvider),
+		// use jwt k8s provider
+		framework.Compose(withJWTK8s, f, common.JSONDataFromSync, useJWTK8sProvider),
+		framework.Compose(withJWTK8s, f, common.JSONDataWithProperty, useJWTK8sProvider),
+		framework.Compose(withJWTK8s, f, common.JSONDataWithTemplate, useJWTK8sProvider),
+		framework.Compose(withJWTK8s, f, common.DataPropertyDockerconfigJSON, useJWTK8sProvider),
+		framework.Compose(withJWTK8s, f, common.JSONDataWithoutTargetName, useJWTK8sProvider),
 		// use kubernetes provider
 		framework.Compose(withK8s, f, common.FindByName, useKubernetesProvider),
 		framework.Compose(withK8s, f, common.JSONDataFromSync, useKubernetesProvider),
@@ -109,6 +116,10 @@ func useJWTProvider(tc *framework.TestCase) {
 	tc.ExternalSecret.Spec.SecretStoreRef.Name = jwtProviderName
 }
 
+func useJWTK8sProvider(tc *framework.TestCase) {
+	tc.ExternalSecret.Spec.SecretStoreRef.Name = jwtK8sProviderName
+}
+
 func useKubernetesProvider(tc *framework.TestCase) {
 	tc.ExternalSecret.Spec.SecretStoreRef.Name = kubernetesProviderName
 }

+ 77 - 6
pkg/provider/vault/vault.go

@@ -29,10 +29,15 @@ import (
 	"github.com/go-logr/logr"
 	vault "github.com/hashicorp/vault/api"
 	"github.com/tidwall/gjson"
+	authenticationv1 "k8s.io/api/authentication/v1"
 	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/kubernetes"
+	typedcorev1 "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"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
@@ -64,10 +69,13 @@ const (
 	errVaultRequest         = "error from Vault request: %w"
 	errVaultResponse        = "cannot parse Vault response: %w"
 	errServiceAccount       = "cannot read Kubernetes service account token from file system: %w"
+	errJwtNoTokenSource     = "neither `secretRef` nor `kubernetesServiceAccountToken` was supplied as token source for jwt authentication"
 	errUnsupportedKvVersion = "cannot perform find operations with kv version v1"
-	errGetKubeSA            = "cannot get Kubernetes service account %q: %w"
-	errGetKubeSASecrets     = "cannot find secrets bound to service account: %q"
-	errGetKubeSANoToken     = "cannot find token in secrets bound to service account: %q"
+
+	errGetKubeSA             = "cannot get Kubernetes service account %q: %w"
+	errGetKubeSASecrets      = "cannot find secrets bound to service account: %q"
+	errGetKubeSANoToken      = "cannot find token in secrets bound to service account: %q"
+	errGetKubeSATokenRequest = "cannot request Kubernetes service account token for service account %q: %w"
 
 	errGetKubeSecret = "cannot get Kubernetes secret %q: %w"
 	errSecretKeyFmt  = "cannot find secret data for key: %q"
@@ -106,6 +114,7 @@ type Client interface {
 
 type client struct {
 	kube      kclient.Client
+	corev1    typedcorev1.CoreV1Interface
 	store     *esv1beta1.VaultProvider
 	log       logr.Logger
 	client    Client
@@ -130,6 +139,21 @@ type connector struct {
 }
 
 func (c *connector) NewClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, namespace string) (esv1beta1.SecretsClient, error) {
+	// 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
+	// (for Kubernetes service account token auth)
+	restCfg, err := ctrlcfg.GetConfig()
+	if err != nil {
+		return nil, err
+	}
+	clientset, err := kubernetes.NewForConfig(restCfg)
+	if err != nil {
+		return nil, err
+	}
+	return c.newClient(ctx, store, kube, clientset.CoreV1(), namespace)
+}
+
+func (c *connector) newClient(ctx context.Context, store esv1beta1.GenericStore, kube kclient.Client, corev1 typedcorev1.CoreV1Interface, namespace string) (esv1beta1.SecretsClient, error) {
 	storeSpec := store.GetSpec()
 	if storeSpec == nil || storeSpec.Provider == nil || storeSpec.Provider.Vault == nil {
 		return nil, errors.New(errVaultStore)
@@ -138,6 +162,7 @@ func (c *connector) NewClient(ctx context.Context, store esv1beta1.GenericStore,
 
 	vStore := &client{
 		kube:      kube,
+		corev1:    corev1,
 		store:     vaultSpec,
 		log:       ctrl.Log.WithName("provider").WithName("vault"),
 		namespace: namespace,
@@ -200,8 +225,16 @@ func (c *connector) ValidateStore(store esv1beta1.GenericStore) error {
 		}
 	}
 	if p.Auth.Jwt != nil {
-		if err := utils.ValidateSecretSelector(store, p.Auth.Jwt.SecretRef); err != nil {
-			return fmt.Errorf(errInvalidJwtSec, err)
+		if p.Auth.Jwt.SecretRef != nil {
+			if err := utils.ValidateSecretSelector(store, *p.Auth.Jwt.SecretRef); err != nil {
+				return fmt.Errorf(errInvalidJwtSec, err)
+			}
+		} else if p.Auth.Jwt.KubernetesServiceAccountToken != nil {
+			if err := utils.ValidateServiceAccountSelector(store, p.Auth.Jwt.KubernetesServiceAccountToken.ServiceAccountRef); err != nil {
+				return fmt.Errorf(errInvalidJwtSec, err)
+			}
+		} else {
+			return fmt.Errorf(errJwtNoTokenSource)
 		}
 	}
 	if p.Auth.Kubernetes != nil {
@@ -822,6 +855,27 @@ func (v *client) secretKeyRef(ctx context.Context, secretRef *esmeta.SecretKeySe
 	return valueStr, nil
 }
 
+func (v *client) serviceAccountToken(ctx context.Context, serviceAccountRef esmeta.ServiceAccountSelector, audiences []string, expirationSeconds int64) (string, error) {
+	tokenRequest := &authenticationv1.TokenRequest{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: v.namespace,
+		},
+		Spec: authenticationv1.TokenRequestSpec{
+			Audiences:         audiences,
+			ExpirationSeconds: &expirationSeconds,
+		},
+	}
+	if (v.storeKind == esv1beta1.ClusterSecretStoreKind) &&
+		(serviceAccountRef.Namespace != nil) {
+		tokenRequest.Namespace = *serviceAccountRef.Namespace
+	}
+	tokenResponse, err := v.corev1.ServiceAccounts(tokenRequest.Namespace).CreateToken(ctx, serviceAccountRef.Name, tokenRequest, metav1.CreateOptions{})
+	if err != nil {
+		return "", fmt.Errorf(errGetKubeSATokenRequest, serviceAccountRef.Name, err)
+	}
+	return tokenResponse.Status.Token, nil
+}
+
 // checkToken does a lookup and checks if the provided token exists.
 func checkToken(ctx context.Context, vStore *client) error {
 	// https://www.vaultproject.io/api-docs/auth/token#lookup-a-token-self
@@ -995,7 +1049,24 @@ func (v *client) requestTokenWithLdapAuth(ctx context.Context, client Client, ld
 func (v *client) requestTokenWithJwtAuth(ctx context.Context, client Client, jwtAuth *esv1beta1.VaultJwtAuth) (string, error) {
 	role := strings.TrimSpace(jwtAuth.Role)
 
-	jwt, err := v.secretKeyRef(ctx, &jwtAuth.SecretRef)
+	var jwt string
+	var err error
+	if jwtAuth.SecretRef != nil {
+		jwt, err = v.secretKeyRef(ctx, jwtAuth.SecretRef)
+	} else if k8sServiceAccountToken := jwtAuth.KubernetesServiceAccountToken; k8sServiceAccountToken != nil {
+		audiences := k8sServiceAccountToken.Audiences
+		if audiences == nil {
+			audiences = &[]string{"vault"}
+		}
+		expirationSeconds := k8sServiceAccountToken.ExpirationSeconds
+		if expirationSeconds == nil {
+			tmp := int64(600)
+			expirationSeconds = &tmp
+		}
+		jwt, err = v.serviceAccountToken(ctx, k8sServiceAccountToken.ServiceAccountRef, *audiences, *expirationSeconds)
+	} else {
+		err = fmt.Errorf(errJwtNoTokenSource)
+	}
 	if err != nil {
 		return "", err
 	}

+ 2 - 2
pkg/provider/vault/vault_test.go

@@ -564,7 +564,7 @@ func vaultTest(t *testing.T, name string, tc testCase) {
 	if tc.args.newClientFunc == nil {
 		conn.newVaultClient = newVaultClient
 	}
-	_, err := conn.NewClient(context.Background(), tc.args.store, tc.args.kube, tc.args.ns)
+	_, err := conn.newClient(context.Background(), tc.args.store, tc.args.kube, nil, tc.args.ns)
 	if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
 		t.Errorf("\n%s\nvault.New(...): -want error, +got error:\n%s", tc.reason, diff)
 	}
@@ -1361,7 +1361,7 @@ func TestValidateStore(t *testing.T) {
 			args: args{
 				auth: esv1beta1.VaultAuth{
 					Jwt: &esv1beta1.VaultJwtAuth{
-						SecretRef: esmeta.SecretKeySelector{
+						SecretRef: &esmeta.SecretKeySelector{
 							Namespace: pointer.StringPtr("invalid"),
 						},
 					},