mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Merge pull request #3348 from Infisical/daniel/k8s-auto-reviewer-token
feat(k8s): k8s auth automatic service account token creation
This commit is contained in:
@@ -264,6 +264,7 @@ The available authentication methods are `universalAuth`, `kubernetesAuth`, `aws
|
||||
- `credentialsRef.secretName`: The name of the Kubernetes secret.
|
||||
- `credentialsRef.secretNamespace`: The namespace of the Kubernetes secret.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
@@ -296,6 +297,9 @@ The available authentication methods are `universalAuth`, `kubernetesAuth`, `aws
|
||||
- `serviceAccountRef`: The name and namespace of the service account that will be used to authenticate with Infisical.
|
||||
- `serviceAccountRef.name`: The name of the service account.
|
||||
- `serviceAccountRef.namespace`: The namespace of the service account.
|
||||
- `autoCreateServiceAccountToken`: If set to `true`, the operator will automatically create a short-lived service account token on-demand for the service account. Defaults to `false`.
|
||||
- `serviceAccountTokenAudiences`: Optionally specify audience for the service account token. This field is only relevant if you have set `autoCreateServiceAccountToken` to `true`. No audience is specified by default.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
@@ -303,6 +307,9 @@ The available authentication methods are `universalAuth`, `kubernetesAuth`, `aws
|
||||
spec:
|
||||
kubernetesAuth:
|
||||
identityId: <machine-identity-id>
|
||||
autoCreateServiceAccountToken: true # Automatically creates short-lived service account tokens for the service account.
|
||||
serviceAccountTokenAudiences:
|
||||
- <audience> # Optionally specify audience for the service account token. No audience is specified by default.
|
||||
serviceAccountRef:
|
||||
name: <secret-name>
|
||||
namespace: <secret-namespace>
|
||||
|
||||
@@ -291,6 +291,8 @@ After applying the InfisicalPushSecret CRD, you should notice that the secrets y
|
||||
- `serviceAccountRef`: The name and namespace of the service account that will be used to authenticate with Infisical.
|
||||
- `serviceAccountRef.name`: The name of the service account.
|
||||
- `serviceAccountRef.namespace`: The namespace of the service account.
|
||||
- `autoCreateServiceAccountToken`: If set to `true`, the operator will automatically create a short-lived service account token on-demand for the service account. Defaults to `false`.
|
||||
- `serviceAccountTokenAudiences`: Optionally specify audience for the service account token. This field is only relevant if you have set `autoCreateServiceAccountToken` to `true`. No audience is specified by default.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -298,6 +300,9 @@ After applying the InfisicalPushSecret CRD, you should notice that the secrets y
|
||||
spec:
|
||||
kubernetesAuth:
|
||||
identityId: <machine-identity-id>
|
||||
autoCreateServiceAccountToken: true # Automatically creates short-lived service account tokens for the service account.
|
||||
serviceAccountTokenAudiences:
|
||||
- <audience> # Optionally specify audience for the service account token. No audience is specified by default.
|
||||
serviceAccountRef:
|
||||
name: <secret-name>
|
||||
namespace: <secret-namespace>
|
||||
|
||||
@@ -156,157 +156,420 @@ spec:
|
||||
<Accordion title="authentication.kubernetesAuth">
|
||||
The Kubernetes machine identity authentication method is used to authenticate with Infisical. The identity ID is stored in a field in the InfisicalSecret resource. This authentication method can only be used within a Kubernetes environment.
|
||||
|
||||
<Steps>
|
||||
<Step title="Obtaining the token reviewer JWT for Infisical">
|
||||
1.1. Start by creating a service account in your Kubernetes cluster that will be used by Infisical to authenticate with the Kubernetes API Server.
|
||||
<Tabs>
|
||||
<Tab title="Short-lived service account tokens (Recommended)">
|
||||
Short-lived service account tokens are automatically created by the operator and are valid only for a short period of time. This is the recommended approach for using Kubernetes auth in the Infisical Secrets Operator.
|
||||
|
||||
```yaml infisical-service-account.yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: infisical-auth
|
||||
namespace: default
|
||||
<Steps>
|
||||
<Step title="Obtaining the token reviewer JWT for Infisical">
|
||||
**1.1.** Start by creating a reviewer service account in your Kubernetes cluster that will be used by Infisical to authenticate with the Kubernetes API Server.
|
||||
|
||||
```
|
||||
```yaml infisical-reviewer-service-account.yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: infisical-token-reviewer
|
||||
namespace: default
|
||||
|
||||
```
|
||||
kubectl apply -f infisical-service-account.yaml
|
||||
```
|
||||
```
|
||||
|
||||
1.2. Bind the service account to the `system:auth-delegator` cluster role. As described [here](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#other-component-roles), this role allows delegated authentication and authorization checks, specifically for Infisical to access the [TokenReview API](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-review-v1/). You can apply the following configuration file:
|
||||
```bash
|
||||
kubectl apply -f infisical-reviewer-service-account.yaml
|
||||
```
|
||||
|
||||
```yaml cluster-role-binding.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: role-tokenreview-binding
|
||||
namespace: default
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:auth-delegator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: infisical-auth
|
||||
namespace: default
|
||||
```
|
||||
**1.2.** Bind the reviewer service account to the `system:auth-delegator` cluster role. As described [here](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#other-component-roles), this role allows delegated authentication and authorization checks, specifically for Infisical to access the [TokenReview API](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-review-v1/). You can apply the following configuration file:
|
||||
|
||||
```
|
||||
kubectl apply -f cluster-role-binding.yaml
|
||||
```
|
||||
```yaml infisical-reviewer-cluster-role-binding.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: infisical-token-reviewer-role-binding
|
||||
namespace: default
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:auth-delegator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: infisical-token-reviewer
|
||||
namespace: default
|
||||
```
|
||||
|
||||
1.3. Next, create a long-lived service account JWT token (i.e. the token reviewer JWT token) for the service account using this configuration file for a new `Secret` resource:
|
||||
```bash
|
||||
kubectl apply -f infisical-reviewer-cluster-role-binding.yaml
|
||||
```
|
||||
|
||||
```yaml service-account-token.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: kubernetes.io/service-account-token
|
||||
metadata:
|
||||
name: infisical-auth-token
|
||||
annotations:
|
||||
kubernetes.io/service-account.name: "infisical-auth"
|
||||
```
|
||||
**1.3.** Next, create a long-lived service account JWT token (i.e. the token reviewer JWT token) for the service account using this configuration file for a new `Secret` resource:
|
||||
|
||||
```yaml service-account-reviewer-token.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: kubernetes.io/service-account-token
|
||||
metadata:
|
||||
name: infisical-token-reviewer-token
|
||||
annotations:
|
||||
kubernetes.io/service-account.name: "infisical-token-reviewer"
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
kubectl apply -f service-account-token.yaml
|
||||
```
|
||||
```bash
|
||||
kubectl apply -f service-account-reviewer-token.yaml
|
||||
```
|
||||
|
||||
1.4. Link the secret in step 1.3 to the service account in step 1.1:
|
||||
**1.4.** Link the secret in step 1.3 to the service account in step 1.1:
|
||||
|
||||
```bash
|
||||
kubectl patch serviceaccount infisical-auth -p '{"secrets": [{"name": "infisical-auth-token"}]}' -n default
|
||||
```
|
||||
```bash
|
||||
kubectl patch serviceaccount infisical-token-reviewer -p '{"secrets": [{"name": "infisical-token-reviewer-token"}]}' -n default
|
||||
```
|
||||
|
||||
1.5. Finally, retrieve the token reviewer JWT token from the secret.
|
||||
**1.5.** Finally, retrieve the token reviewer JWT token from the secret.
|
||||
|
||||
```bash
|
||||
kubectl get secret infisical-auth-token -n default -o=jsonpath='{.data.token}' | base64 --decode
|
||||
```
|
||||
```bash
|
||||
kubectl get secret infisical-token-reviewer-token -n default -o=jsonpath='{.data.token}' | base64 --decode
|
||||
```
|
||||
|
||||
Keep this JWT token handy as you will need it for the **Token Reviewer JWT** field when configuring the Kubernetes Auth authentication method for the identity in step 2.
|
||||
Keep this JWT token handy as you will need it for the **Token Reviewer JWT** field when configuring the Kubernetes Auth authentication method for the identity in step 2.
|
||||
</Step>
|
||||
|
||||
</Step>
|
||||
<Step title="Creating an identity">
|
||||
To create an identity, head to your Organization Settings > Access Control > Machine Identities and press **Create identity**.
|
||||
|
||||
<Step title="Creating an identity">
|
||||
To create an identity, head to your Organization Settings > Access Control > Machine Identities and press **Create identity**.
|
||||

|
||||
|
||||

|
||||
When creating an identity, you specify an organization level [role](/documentation/platform/role-based-access-controls) for it to assume; you can configure roles in Organization Settings > Access Control > Organization Roles.
|
||||
|
||||
When creating an identity, you specify an organization level [role](/documentation/platform/role-based-access-controls) for it to assume; you can configure roles in Organization Settings > Access Control > Organization Roles.
|
||||

|
||||
|
||||

|
||||
Now input a few details for your new identity. Here's some guidance for each field:
|
||||
|
||||
Now input a few details for your new identity. Here's some guidance for each field:
|
||||
- Name (required): A friendly name for the identity.
|
||||
- Role (required): A role from the **Organization Roles** tab for the identity to assume. The organization role assigned will determine what organization level resources this identity can have access to.
|
||||
|
||||
- Name (required): A friendly name for the identity.
|
||||
- Role (required): A role from the **Organization Roles** tab for the identity to assume. The organization role assigned will determine what organization level resources this identity can have access to.
|
||||
Once you've created an identity, you'll be prompted to configure the authentication method for it. Here, select **Kubernetes Auth**.
|
||||
|
||||
Once you've created an identity, you'll be prompted to configure the authentication method for it. Here, select **Kubernetes Auth**.
|
||||
<Info>
|
||||
To learn more about each field of the Kubernetes native authentication method, see step 2 of [guide](/documentation/platform/identities/kubernetes-auth#guide).
|
||||
</Info>
|
||||
|
||||
<Info>
|
||||
To learn more about each field of the Kubernetes native authentication method, see step 2 of [guide](/documentation/platform/identities/kubernetes-auth#guide).
|
||||
</Info>
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
</Step>
|
||||
<Step title="Adding an identity to a project">
|
||||
To allow the operator to use the given identity to access secrets, you will need to add the identity to project(s) that you would like to grant it access to.
|
||||
</Step>
|
||||
<Step title="Adding an identity to a project">
|
||||
To allow the operator to use the given identity to access secrets, you will need to add the identity to project(s) that you would like to grant it access to.
|
||||
|
||||
To do this, head over to the project you want to add the identity to and go to Project Settings > Access Control > Machine Identities and press **Add identity**.
|
||||
To do this, head over to the project you want to add the identity to and go to Project Settings > Access Control > Machine Identities and press **Add identity**.
|
||||
|
||||
Next, select the identity you want to add to the project and the project level role you want to allow it to assume. The project role assigned will determine what project level resources this identity can have access to.
|
||||
Next, select the identity you want to add to the project and the project level role you want to allow it to assume. The project role assigned will determine what project level resources this identity can have access to.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
</Step>
|
||||
<Step title="Add your identity ID & service account to your InfisicalSecret resource">
|
||||
Once you have created your machine identity and added it to your project(s), you will need to add the identity ID to your InfisicalSecret resource.
|
||||
In the `authentication.kubernetesAuth.identityId` field, add the identity ID of the machine identity you created.
|
||||
See the example below for more details.
|
||||
</Step>
|
||||
<Step title="Add your Kubernetes service account token to the InfisicalSecret resource">
|
||||
Add the service account details from the previous steps under `authentication.kubernetesAuth.serviceAccountRef`.
|
||||
Here you will need to enter the name and namespace of the service account.
|
||||
The example below shows a complete InfisicalSecret resource with all required fields defined.
|
||||
</Step>
|
||||
</Step>
|
||||
|
||||
</Steps>
|
||||
<Step title="Create a new Kubernetes service account to authenticate with Infisical">
|
||||
You have already created the reviewer service account in step **1.1**. Now, create a new Kubernetes service account that will be used to authenticate with Infisical.
|
||||
This service account will create short-lived tokens that will be used to authenticate with Infisical. The operator itself will handle the creation of these tokens automatically.
|
||||
|
||||
<Info>
|
||||
Make sure to also populate the `secretsScope` field with the project slug
|
||||
_`projectSlug`_, environment slug _`envSlug`_, and secrets path
|
||||
_`secretsPath`_ that you want to fetch secrets from. Please see the example
|
||||
below.
|
||||
</Info>
|
||||
```yaml infisical-service-account.yaml
|
||||
kind: ServiceAccount
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: infisical-service-account
|
||||
```
|
||||
|
||||
## Example
|
||||
```bash
|
||||
kubectl apply -f infisical-service-account.yaml -n default
|
||||
```
|
||||
|
||||
```yaml example-kubernetes-auth.yaml
|
||||
apiVersion: secrets.infisical.com/v1alpha1
|
||||
kind: InfisicalSecret
|
||||
metadata:
|
||||
name: infisicalsecret-sample-crd
|
||||
spec:
|
||||
authentication:
|
||||
kubernetesAuth:
|
||||
identityId: <machine-identity-id>
|
||||
serviceAccountRef:
|
||||
name: <service-account-name>
|
||||
namespace: <service-account-namespace>
|
||||
</Step>
|
||||
|
||||
# secretsScope is identical to the secrets scope in the universalAuth field in this sample.
|
||||
secretsScope:
|
||||
projectSlug: your-project-slug
|
||||
envSlug: prod
|
||||
secretsPath: "/path"
|
||||
recursive: true
|
||||
...
|
||||
```
|
||||
<Step title="Add your identity ID & service account to your InfisicalSecret resource">
|
||||
Once you have created your machine identity and added it to your project(s), you will need to add the identity ID to your InfisicalSecret resource.
|
||||
In the `authentication.kubernetesAuth.identityId` field, add the identity ID of the machine identity you created.
|
||||
See the example below for more details.
|
||||
</Step>
|
||||
<Step title="Add your Kubernetes service account token to the InfisicalSecret resource">
|
||||
Add the service account details from the previous steps under `authentication.kubernetesAuth.serviceAccountRef`.
|
||||
Here you will need to enter the name and namespace of the service account.
|
||||
The example below shows a complete InfisicalSecret resource with all required fields defined.
|
||||
Make sure you set `authentication.kubernetesAuth.autoCreateServiceAccountToken` to `true` to automatically create short-lived service account tokens for the service account.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Info>
|
||||
Make sure to also populate the `secretsScope` field with the project slug
|
||||
_`projectSlug`_, environment slug _`envSlug`_, and secrets path
|
||||
_`secretsPath`_ that you want to fetch secrets from. Please see the example
|
||||
below.
|
||||
</Info>
|
||||
|
||||
## Example
|
||||
|
||||
```yaml example-kubernetes-auth.yaml
|
||||
apiVersion: secrets.infisical.com/v1alpha1
|
||||
kind: InfisicalSecret
|
||||
metadata:
|
||||
name: infisicalsecret-sample-crd
|
||||
spec:
|
||||
authentication:
|
||||
kubernetesAuth:
|
||||
identityId: <machine-identity-id>
|
||||
autoCreateServiceAccountToken: true # Automatically creates short-lived service account tokens for the service account.
|
||||
serviceAccountTokenAudiences:
|
||||
- <audience> # Optionally specify audience for the service account token. No audience is specified by default.
|
||||
serviceAccountRef:
|
||||
name: infisical-service-account # The service account we just created in the previous step.
|
||||
namespace: <service-account-namespace>
|
||||
|
||||
# secretsScope is identical to the secrets scope in the universalAuth field in this sample.
|
||||
secretsScope:
|
||||
projectSlug: your-project-slug
|
||||
envSlug: prod
|
||||
secretsPath: "/path"
|
||||
recursive: true
|
||||
...
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Manual long-lived service account tokens">
|
||||
Manual long-lived service account tokens are manually created by the user and are valid indefinitely unless deleted or rotated. In most cases, you should be using the automatic short-lived service account tokens as they are more secure and easier to use.
|
||||
<Steps>
|
||||
<Step title="Obtaining the token reviewer JWT for Infisical">
|
||||
**1.1.** Start by creating a reviewer service account in your Kubernetes cluster that will be used by Infisical to authenticate with the Kubernetes API Server.
|
||||
|
||||
```yaml infisical-reviewer-service-account.yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: infisical-token-reviewer
|
||||
namespace: default
|
||||
|
||||
```
|
||||
|
||||
```bash
|
||||
kubectl apply -f infisical-reviewer-service-account.yaml
|
||||
```
|
||||
|
||||
**1.2.** Bind the reviewer service account to the `system:auth-delegator` cluster role. As described [here](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#other-component-roles), this role allows delegated authentication and authorization checks, specifically for Infisical to access the [TokenReview API](https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-review-v1/). You can apply the following configuration file:
|
||||
|
||||
```yaml infisical-reviewer-cluster-role-binding.yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: infisical-token-reviewer-role-binding
|
||||
namespace: default
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:auth-delegator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: infisical-token-reviewer
|
||||
namespace: default
|
||||
```
|
||||
|
||||
```bash
|
||||
kubectl apply -f infisical-reviewer-cluster-role-binding.yaml
|
||||
```
|
||||
|
||||
**1.3.** Next, create a long-lived service account JWT token (i.e. the token reviewer JWT token) for the service account using this configuration file for a new `Secret` resource:
|
||||
|
||||
```yaml service-account-reviewer-token.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: kubernetes.io/service-account-token
|
||||
metadata:
|
||||
name: infisical-token-reviewer-token
|
||||
annotations:
|
||||
kubernetes.io/service-account.name: "infisical-token-reviewer"
|
||||
```
|
||||
|
||||
|
||||
```bash
|
||||
kubectl apply -f service-account-reviewer-token.yaml
|
||||
```
|
||||
|
||||
**1.4.** Link the secret in step 1.3 to the service account in step 1.1:
|
||||
|
||||
```bash
|
||||
kubectl patch serviceaccount infisical-token-reviewer -p '{"secrets": [{"name": "infisical-token-reviewer-token"}]}' -n default
|
||||
```
|
||||
|
||||
**1.5.** Finally, retrieve the token reviewer JWT token from the secret.
|
||||
|
||||
```bash
|
||||
kubectl get secret infisical-token-reviewer-token -n default -o=jsonpath='{.data.token}' | base64 --decode
|
||||
```
|
||||
|
||||
Keep this JWT token handy as you will need it for the **Token Reviewer JWT** field when configuring the Kubernetes Auth authentication method for the identity in step 2.
|
||||
</Step>
|
||||
|
||||
<Step title="Creating an identity">
|
||||
To create an identity, head to your Organization Settings > Access Control > Machine Identities and press **Create identity**.
|
||||
|
||||

|
||||
|
||||
When creating an identity, you specify an organization level [role](/documentation/platform/role-based-access-controls) for it to assume; you can configure roles in Organization Settings > Access Control > Organization Roles.
|
||||
|
||||

|
||||
|
||||
Now input a few details for your new identity. Here's some guidance for each field:
|
||||
|
||||
- Name (required): A friendly name for the identity.
|
||||
- Role (required): A role from the **Organization Roles** tab for the identity to assume. The organization role assigned will determine what organization level resources this identity can have access to.
|
||||
|
||||
Once you've created an identity, you'll be prompted to configure the authentication method for it. Here, select **Kubernetes Auth**.
|
||||
|
||||
<Info>
|
||||
To learn more about each field of the Kubernetes native authentication method, see step 2 of [guide](/documentation/platform/identities/kubernetes-auth#guide).
|
||||
</Info>
|
||||
|
||||

|
||||
|
||||
|
||||
</Step>
|
||||
<Step title="Adding an identity to a project">
|
||||
To allow the operator to use the given identity to access secrets, you will need to add the identity to project(s) that you would like to grant it access to.
|
||||
|
||||
To do this, head over to the project you want to add the identity to and go to Project Settings > Access Control > Machine Identities and press **Add identity**.
|
||||
|
||||
Next, select the identity you want to add to the project and the project level role you want to allow it to assume. The project role assigned will determine what project level resources this identity can have access to.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Create a new Kubernetes service account to authenticate with Infisical">
|
||||
You have already created the reviewer service account in step **1.1**. Now, create a new Kubernetes service account that will be used to authenticate with Infisical.
|
||||
|
||||
```yaml infisical-service-account.yaml
|
||||
kind: ServiceAccount
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: infisical-service-account
|
||||
```
|
||||
|
||||
```bash
|
||||
kubectl apply -f infisical-service-account.yaml -n default
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a service account token for the Kubernetes service account">
|
||||
Create a service account token for the newly created Kubernetes service account from the previous step.
|
||||
|
||||
```yaml infisical-service-account-token.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: kubernetes.io/service-account-token
|
||||
metadata:
|
||||
name: infisical-service-account-token
|
||||
annotations:
|
||||
kubernetes.io/service-account.name: "infisical-service-account"
|
||||
```
|
||||
|
||||
```bash
|
||||
kubectl apply -f infisical-service-account-token.yaml -n default
|
||||
```
|
||||
|
||||
Patch the service account with the newly created service account token.
|
||||
|
||||
```bash
|
||||
kubectl patch serviceaccount infisical-service-account -p '{"secrets": [{"name": "infisical-service-account-token"}]}' -n default
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Add your identity ID & service account to your InfisicalSecret resource">
|
||||
Once you have created your machine identity and added it to your project(s), you will need to add the identity ID to your InfisicalSecret resource.
|
||||
In the `authentication.kubernetesAuth.identityId` field, add the identity ID of the machine identity you created.
|
||||
See the example below for more details.
|
||||
</Step>
|
||||
<Step title="Add your Kubernetes service account token to the InfisicalSecret resource">
|
||||
Add the service account details from the previous steps under `authentication.kubernetesAuth.serviceAccountRef`.
|
||||
Here you will need to enter the name and namespace of the service account.
|
||||
The example below shows a complete InfisicalSecret resource with all required fields defined.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Info>
|
||||
Make sure to also populate the `secretsScope` field with the project slug
|
||||
_`projectSlug`_, environment slug _`envSlug`_, and secrets path
|
||||
_`secretsPath`_ that you want to fetch secrets from. Please see the example
|
||||
below.
|
||||
</Info>
|
||||
|
||||
## Example
|
||||
|
||||
```yaml example-kubernetes-auth.yaml
|
||||
apiVersion: secrets.infisical.com/v1alpha1
|
||||
kind: InfisicalSecret
|
||||
metadata:
|
||||
name: infisicalsecret-sample-crd
|
||||
spec:
|
||||
authentication:
|
||||
kubernetesAuth:
|
||||
identityId: <machine-identity-id>
|
||||
serviceAccountRef:
|
||||
name: infisical-service-account # The service account we just created in the previous step. (*not* the reviewer service account)
|
||||
namespace: <service-account-namespace>
|
||||
|
||||
# secretsScope is identical to the secrets scope in the universalAuth field in this sample.
|
||||
secretsScope:
|
||||
projectSlug: your-project-slug
|
||||
envSlug: prod
|
||||
secretsPath: "/path"
|
||||
recursive: true
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
</Accordion>
|
||||
|
||||
|
||||
3
k8-operator/.gitignore
vendored
3
k8-operator/.gitignore
vendored
@@ -24,3 +24,6 @@ Dockerfile.cross
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Testing directories
|
||||
auto-token
|
||||
@@ -49,6 +49,14 @@ type GenericKubernetesAuth struct {
|
||||
IdentityID string `json:"identityId"`
|
||||
// +kubebuilder:validation:Required
|
||||
ServiceAccountRef KubernetesServiceAccountRef `json:"serviceAccountRef"`
|
||||
|
||||
// Optionally automatically create a service account token for the configured service account.
|
||||
// If this is set to `true`, the operator will automatically create a service account token for the configured service account. This field is recommended in most cases.
|
||||
// +kubebuilder:validation:Optional
|
||||
AutoCreateServiceAccountToken bool `json:"autoCreateServiceAccountToken"`
|
||||
// The audiences to use for the service account token. This is only relevant if `autoCreateServiceAccountToken` is true.
|
||||
// +kubebuilder:validation:Optional
|
||||
ServiceAccountTokenAudiences []string `json:"serviceAccountTokenAudiences"`
|
||||
}
|
||||
|
||||
type TLSConfig struct {
|
||||
|
||||
@@ -38,6 +38,14 @@ type KubernetesAuthDetails struct {
|
||||
|
||||
// +kubebuilder:validation:Required
|
||||
SecretsScope MachineIdentityScopeInWorkspace `json:"secretsScope"`
|
||||
|
||||
// Optionally automatically create a service account token for the configured service account.
|
||||
// If this is set to `true`, the operator will automatically create a service account token for the configured service account.
|
||||
// +kubebuilder:validation:Optional
|
||||
AutoCreateServiceAccountToken bool `json:"autoCreateServiceAccountToken"`
|
||||
// The audiences to use for the service account token. This is only relevant if `autoCreateServiceAccountToken` is true.
|
||||
// +kubebuilder:validation:Optional
|
||||
ServiceAccountTokenAudiences []string `json:"serviceAccountTokenAudiences"`
|
||||
}
|
||||
|
||||
type KubernetesServiceAccountRef struct {
|
||||
|
||||
@@ -48,7 +48,7 @@ func (in *Authentication) DeepCopyInto(out *Authentication) {
|
||||
out.ServiceAccount = in.ServiceAccount
|
||||
out.ServiceToken = in.ServiceToken
|
||||
out.UniversalAuth = in.UniversalAuth
|
||||
out.KubernetesAuth = in.KubernetesAuth
|
||||
in.KubernetesAuth.DeepCopyInto(&out.KubernetesAuth)
|
||||
out.AwsIamAuth = in.AwsIamAuth
|
||||
out.AzureAuth = in.AzureAuth
|
||||
out.GcpIdTokenAuth = in.GcpIdTokenAuth
|
||||
@@ -207,7 +207,7 @@ func (in *GenericGcpIdTokenAuth) DeepCopy() *GenericGcpIdTokenAuth {
|
||||
func (in *GenericInfisicalAuthentication) DeepCopyInto(out *GenericInfisicalAuthentication) {
|
||||
*out = *in
|
||||
out.UniversalAuth = in.UniversalAuth
|
||||
out.KubernetesAuth = in.KubernetesAuth
|
||||
in.KubernetesAuth.DeepCopyInto(&out.KubernetesAuth)
|
||||
out.AwsIamAuth = in.AwsIamAuth
|
||||
out.AzureAuth = in.AzureAuth
|
||||
out.GcpIdTokenAuth = in.GcpIdTokenAuth
|
||||
@@ -228,6 +228,11 @@ func (in *GenericInfisicalAuthentication) DeepCopy() *GenericInfisicalAuthentica
|
||||
func (in *GenericKubernetesAuth) DeepCopyInto(out *GenericKubernetesAuth) {
|
||||
*out = *in
|
||||
out.ServiceAccountRef = in.ServiceAccountRef
|
||||
if in.ServiceAccountTokenAudiences != nil {
|
||||
in, out := &in.ServiceAccountTokenAudiences, &out.ServiceAccountTokenAudiences
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericKubernetesAuth.
|
||||
@@ -336,7 +341,7 @@ func (in *InfisicalDynamicSecretList) DeepCopyObject() runtime.Object {
|
||||
func (in *InfisicalDynamicSecretSpec) DeepCopyInto(out *InfisicalDynamicSecretSpec) {
|
||||
*out = *in
|
||||
in.ManagedSecretReference.DeepCopyInto(&out.ManagedSecretReference)
|
||||
out.Authentication = in.Authentication
|
||||
in.Authentication.DeepCopyInto(&out.Authentication)
|
||||
out.DynamicSecret = in.DynamicSecret
|
||||
out.TLS = in.TLS
|
||||
}
|
||||
@@ -476,7 +481,7 @@ func (in *InfisicalPushSecretSecretSource) DeepCopy() *InfisicalPushSecretSecret
|
||||
func (in *InfisicalPushSecretSpec) DeepCopyInto(out *InfisicalPushSecretSpec) {
|
||||
*out = *in
|
||||
out.Destination = in.Destination
|
||||
out.Authentication = in.Authentication
|
||||
in.Authentication.DeepCopyInto(&out.Authentication)
|
||||
in.Push.DeepCopyInto(&out.Push)
|
||||
out.TLS = in.TLS
|
||||
}
|
||||
@@ -583,7 +588,7 @@ func (in *InfisicalSecretList) DeepCopyObject() runtime.Object {
|
||||
func (in *InfisicalSecretSpec) DeepCopyInto(out *InfisicalSecretSpec) {
|
||||
*out = *in
|
||||
out.TokenSecretReference = in.TokenSecretReference
|
||||
out.Authentication = in.Authentication
|
||||
in.Authentication.DeepCopyInto(&out.Authentication)
|
||||
in.ManagedSecretReference.DeepCopyInto(&out.ManagedSecretReference)
|
||||
if in.ManagedKubeSecretReferences != nil {
|
||||
in, out := &in.ManagedKubeSecretReferences, &out.ManagedKubeSecretReferences
|
||||
@@ -654,6 +659,11 @@ func (in *KubernetesAuthDetails) DeepCopyInto(out *KubernetesAuthDetails) {
|
||||
*out = *in
|
||||
out.ServiceAccountRef = in.ServiceAccountRef
|
||||
out.SecretsScope = in.SecretsScope
|
||||
if in.ServiceAccountTokenAudiences != nil {
|
||||
in, out := &in.ServiceAccountTokenAudiences, &out.ServiceAccountTokenAudiences
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesAuthDetails.
|
||||
|
||||
@@ -73,6 +73,12 @@ spec:
|
||||
type: object
|
||||
kubernetesAuth:
|
||||
properties:
|
||||
autoCreateServiceAccountToken:
|
||||
description: Optionally automatically create a service account
|
||||
token for the configured service account. If this is set
|
||||
to `true`, the operator will automatically create a service
|
||||
account token for the configured service account.
|
||||
type: boolean
|
||||
identityId:
|
||||
type: string
|
||||
serviceAccountRef:
|
||||
@@ -85,6 +91,13 @@ spec:
|
||||
- name
|
||||
- namespace
|
||||
type: object
|
||||
serviceAccountTokenAudiences:
|
||||
description: The audiences to use for the service account
|
||||
token. This is only relevant if `autoCreateServiceAccountToken`
|
||||
is true.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- identityId
|
||||
- serviceAccountRef
|
||||
|
||||
@@ -73,6 +73,12 @@ spec:
|
||||
type: object
|
||||
kubernetesAuth:
|
||||
properties:
|
||||
autoCreateServiceAccountToken:
|
||||
description: Optionally automatically create a service account
|
||||
token for the configured service account. If this is set
|
||||
to `true`, the operator will automatically create a service
|
||||
account token for the configured service account.
|
||||
type: boolean
|
||||
identityId:
|
||||
type: string
|
||||
serviceAccountRef:
|
||||
@@ -85,6 +91,13 @@ spec:
|
||||
- name
|
||||
- namespace
|
||||
type: object
|
||||
serviceAccountTokenAudiences:
|
||||
description: The audiences to use for the service account
|
||||
token. This is only relevant if `autoCreateServiceAccountToken`
|
||||
is true.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- identityId
|
||||
- serviceAccountRef
|
||||
|
||||
@@ -136,6 +136,12 @@ spec:
|
||||
type: object
|
||||
kubernetesAuth:
|
||||
properties:
|
||||
autoCreateServiceAccountToken:
|
||||
description: Optionally automatically create a service account
|
||||
token for the configured service account. If this is set
|
||||
to `true`, the operator will automatically create a service
|
||||
account token for the configured service account.
|
||||
type: boolean
|
||||
identityId:
|
||||
type: string
|
||||
secretsScope:
|
||||
@@ -163,6 +169,13 @@ spec:
|
||||
- name
|
||||
- namespace
|
||||
type: object
|
||||
serviceAccountTokenAudiences:
|
||||
description: The audiences to use for the service account
|
||||
token. This is only relevant if `autoCreateServiceAccountToken`
|
||||
is true.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- identityId
|
||||
- secretsScope
|
||||
|
||||
@@ -16,6 +16,13 @@ rules:
|
||||
- list
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
@@ -35,6 +42,12 @@ rules:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- serviceaccounts/token
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
@@ -55,6 +68,12 @@ rules:
|
||||
- list
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- secrets.infisical.com
|
||||
resources:
|
||||
|
||||
@@ -45,6 +45,9 @@ func (r *InfisicalDynamicSecretReconciler) GetLogger(req ctrl.Request) logr.Logg
|
||||
// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;delete
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;watch;get;update
|
||||
// +kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch
|
||||
//+kubebuilder:rbac:groups="",resources=pods,verbs=get;list
|
||||
//+kubebuilder:rbac:groups="authentication.k8s.io",resources=tokenreviews,verbs=create
|
||||
//+kubebuilder:rbac:groups="",resources=serviceaccounts/token,verbs=create
|
||||
|
||||
func (r *InfisicalDynamicSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ func (r *InfisicalPushSecretReconciler) GetLogger(req ctrl.Request) logr.Logger
|
||||
//+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;delete
|
||||
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;watch;get;update
|
||||
//+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch
|
||||
//+kubebuilder:rbac:groups="",resources=pods,verbs=get;list
|
||||
//+kubebuilder:rbac:groups="authentication.k8s.io",resources=tokenreviews,verbs=create
|
||||
//+kubebuilder:rbac:groups="",resources=serviceaccounts/token,verbs=create
|
||||
|
||||
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||
// move the current state of the cluster closer to the desired state.
|
||||
|
||||
@@ -44,6 +44,9 @@ func (r *InfisicalSecretReconciler) GetLogger(req ctrl.Request) logr.Logger {
|
||||
//+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;delete
|
||||
//+kubebuilder:rbac:groups=apps,resources=deployments;daemonsets;statefulsets,verbs=list;watch;get;update
|
||||
//+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch
|
||||
//+kubebuilder:rbac:groups="",resources=pods,verbs=get;list
|
||||
//+kubebuilder:rbac:groups="authentication.k8s.io",resources=tokenreviews,verbs=create
|
||||
//+kubebuilder:rbac:groups="",resources=serviceaccounts/token,verbs=create
|
||||
|
||||
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||
// move the current state of the cluster closer to the desired state.
|
||||
|
||||
@@ -8,12 +8,51 @@ import (
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
|
||||
"github.com/Infisical/infisical/k8-operator/api/v1alpha1"
|
||||
"github.com/aws/smithy-go/ptr"
|
||||
infisicalSdk "github.com/infisical/go-sdk"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func GetServiceAccountToken(k8sClient client.Client, namespace string, serviceAccountName string) (string, error) {
|
||||
func GetServiceAccountToken(k8sClient client.Client, namespace string, serviceAccountName string, autoCreateServiceAccountToken bool, serviceAccountTokenAudiences []string) (string, error) {
|
||||
|
||||
if autoCreateServiceAccountToken {
|
||||
restClient, err := GetRestClientFromClient()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get REST client: %w", err)
|
||||
}
|
||||
|
||||
tokenRequest := &authenticationv1.TokenRequest{
|
||||
Spec: authenticationv1.TokenRequestSpec{
|
||||
ExpirationSeconds: ptr.Int64(600), // 10 minutes. the token only needs to be valid for when we do the initial k8s login.
|
||||
},
|
||||
}
|
||||
|
||||
if len(serviceAccountTokenAudiences) > 0 {
|
||||
// Conditionally add the audiences if they are specified.
|
||||
// Failing to do this causes a default audience to be used, which is not what we want if the user doesn't specify any.
|
||||
tokenRequest.Spec.Audiences = serviceAccountTokenAudiences
|
||||
}
|
||||
|
||||
result := &authenticationv1.TokenRequest{}
|
||||
err = restClient.
|
||||
Post().
|
||||
Namespace(namespace).
|
||||
Resource("serviceaccounts").
|
||||
Name(serviceAccountName).
|
||||
SubResource("token").
|
||||
Body(tokenRequest).
|
||||
Do(context.Background()).
|
||||
Into(result)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create token: %w", err)
|
||||
}
|
||||
|
||||
return result.Status.Token, nil
|
||||
}
|
||||
|
||||
serviceAccount := &corev1.ServiceAccount{}
|
||||
err := k8sClient.Get(context.TODO(), client.ObjectKey{Name: serviceAccountName, Namespace: namespace}, serviceAccount)
|
||||
@@ -172,7 +211,9 @@ func HandleKubernetesAuth(ctx context.Context, reconcilerClient client.Client, s
|
||||
Namespace: infisicalPushSecret.Spec.Authentication.KubernetesAuth.ServiceAccountRef.Namespace,
|
||||
Name: infisicalPushSecret.Spec.Authentication.KubernetesAuth.ServiceAccountRef.Name,
|
||||
},
|
||||
SecretsScope: v1alpha1.MachineIdentityScopeInWorkspace{},
|
||||
SecretsScope: v1alpha1.MachineIdentityScopeInWorkspace{},
|
||||
AutoCreateServiceAccountToken: infisicalPushSecret.Spec.Authentication.KubernetesAuth.AutoCreateServiceAccountToken,
|
||||
ServiceAccountTokenAudiences: infisicalPushSecret.Spec.Authentication.KubernetesAuth.ServiceAccountTokenAudiences,
|
||||
}
|
||||
|
||||
case SecretCrd.INFISICAL_DYNAMIC_SECRET:
|
||||
@@ -188,7 +229,9 @@ func HandleKubernetesAuth(ctx context.Context, reconcilerClient client.Client, s
|
||||
Namespace: infisicalDynamicSecret.Spec.Authentication.KubernetesAuth.ServiceAccountRef.Namespace,
|
||||
Name: infisicalDynamicSecret.Spec.Authentication.KubernetesAuth.ServiceAccountRef.Name,
|
||||
},
|
||||
SecretsScope: v1alpha1.MachineIdentityScopeInWorkspace{},
|
||||
SecretsScope: v1alpha1.MachineIdentityScopeInWorkspace{},
|
||||
AutoCreateServiceAccountToken: infisicalDynamicSecret.Spec.Authentication.KubernetesAuth.AutoCreateServiceAccountToken,
|
||||
ServiceAccountTokenAudiences: infisicalDynamicSecret.Spec.Authentication.KubernetesAuth.ServiceAccountTokenAudiences,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +239,14 @@ func HandleKubernetesAuth(ctx context.Context, reconcilerClient client.Client, s
|
||||
return AuthenticationDetails{}, ErrAuthNotApplicable
|
||||
}
|
||||
|
||||
serviceAccountToken, err := GetServiceAccountToken(reconcilerClient, kubernetesAuthSpec.ServiceAccountRef.Namespace, kubernetesAuthSpec.ServiceAccountRef.Name)
|
||||
serviceAccountToken, err := GetServiceAccountToken(
|
||||
reconcilerClient,
|
||||
kubernetesAuthSpec.ServiceAccountRef.Namespace,
|
||||
kubernetesAuthSpec.ServiceAccountRef.Name,
|
||||
kubernetesAuthSpec.AutoCreateServiceAccountToken,
|
||||
kubernetesAuthSpec.ServiceAccountTokenAudiences,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return AuthenticationDetails{}, fmt.Errorf("unable to get service account token [err=%s]", err)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8Errors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
@@ -58,3 +61,32 @@ func GetInfisicalUniversalAuthFromKubeSecret(ctx context.Context, reconcilerClie
|
||||
return model.MachineIdentityDetails{ClientId: string(clientIdFromSecret), ClientSecret: string(clientSecretFromSecret)}, nil
|
||||
|
||||
}
|
||||
|
||||
func getKubeClusterConfig() (*rest.Config, error) {
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
configOverrides := &clientcmd.ConfigOverrides{}
|
||||
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
|
||||
return kubeConfig.ClientConfig()
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func GetRestClientFromClient() (rest.Interface, error) {
|
||||
|
||||
config, err := getKubeClusterConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return clientset.CoreV1().RESTClient(), nil
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user