docs/integrations/platforms/kubernetes/infisical-static-secret-crd.mdx
import KubernetesOperatorTemplating from "/snippets/kubernetes-operator-v1beta1-templating.mdx";
The InfisicalStaticSecret CRD syncs secrets from Infisical into your Kubernetes cluster as native Kubernetes Secrets or ConfigMaps.
It replaces the v1alpha1 InfisicalSecret CRD with a cleaner design: authentication and connection details are defined as separate reusable resources (InfisicalAuth and InfisicalConnection) instead of inline blocks.
Before creating an InfisicalStaticSecret, you need:
Each example below contains every resource you need to apply: the credential Secret, InfisicalConnection, InfisicalAuth, and InfisicalStaticSecret.
Copy the one that matches your environment, replace the placeholder values, and kubectl apply -f it.
For more details on each resource, see the InfisicalConnection and InfisicalAuth documentation or access our samples.
<AccordionGroup> <Accordion title="Kubernetes Auth (Recommended)"> Best for workloads already running in Kubernetes.This example uses **short-lived service account tokens**. If you prefer to use a Gateway as the token reviewer instead, see the [Kubernetes Auth guide](/documentation/platform/identities/kubernetes-auth) for alternative setup options.
```yaml complete-kubernetes-auth.yaml
# 1. Service account used by the operator for token review
apiVersion: v1
kind: ServiceAccount
metadata:
name: infisical-service-account
namespace: default
---
# 2. Bind the service account to system:auth-delegator so it can
# validate tokens via the Kubernetes TokenReview API
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: infisical-service-account-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: infisical-service-account
namespace: default
---
# 3. Kubernetes secret holding the machine identity ID
apiVersion: v1
kind: Secret
metadata:
name: kubernetes-credentials
namespace: default
type: Opaque
stringData:
identityId: <your-machine-identity-id>
---
# 4. Connection to the Infisical instance
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalConnection
metadata:
name: my-infisical-connection
namespace: default
spec:
address: https://app.infisical.com
---
# 5. Auth using a Kubernetes service account token
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalAuth
metadata:
name: my-infisical-auth
namespace: default
spec:
infisicalConnectionRef:
name: my-infisical-connection
namespace: default
method: kubernetes
kubernetes:
identityIdRef:
name: kubernetes-credentials
namespace: default
key: identityId
serviceAccountRef:
name: infisical-service-account
namespace: default
---
# 6. Sync secrets into a native Kubernetes Secret
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
namespace: default
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
syncOptions:
refreshInterval: 60s
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
```
```yaml complete-universal-auth.yaml
# 1. Kubernetes secret holding the client credentials
apiVersion: v1
kind: Secret
metadata:
name: universal-auth-credentials
namespace: default
type: Opaque
stringData:
clientId: <your-identity-client-id>
clientSecret: <your-identity-client-secret>
---
# 2. Connection to the Infisical instance
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalConnection
metadata:
name: my-infisical-connection
namespace: default
spec:
address: https://app.infisical.com
---
# 3. Auth using Universal Auth credentials
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalAuth
metadata:
name: my-infisical-auth
namespace: default
spec:
infisicalConnectionRef:
name: my-infisical-connection
namespace: default
method: universal
universal:
clientIdRef:
name: universal-auth-credentials
namespace: default
key: clientId
clientSecretRef:
name: universal-auth-credentials
namespace: default
key: clientSecret
---
# 4. Sync secrets into a native Kubernetes Secret
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
namespace: default
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
syncOptions:
refreshInterval: 60s
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
```
```yaml complete-aws-iam-auth.yaml
# 1. Kubernetes secret holding the machine identity ID
apiVersion: v1
kind: Secret
metadata:
name: aws-iam-credentials
namespace: default
type: Opaque
stringData:
identityId: <your-machine-identity-id>
---
# 2. Connection to the Infisical instance
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalConnection
metadata:
name: my-infisical-connection
namespace: default
spec:
address: https://app.infisical.com
---
# 3. Auth using AWS IAM
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalAuth
metadata:
name: my-infisical-auth
namespace: default
spec:
infisicalConnectionRef:
name: my-infisical-connection
namespace: default
method: aws-iam
awsIam:
identityIdRef:
name: aws-iam-credentials
namespace: default
key: identityId
---
# 4. Sync secrets into a native Kubernetes Secret
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
namespace: default
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
syncOptions:
refreshInterval: 60s
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
```
```yaml complete-azure-auth.yaml
# 1. Kubernetes secret holding the machine identity ID
apiVersion: v1
kind: Secret
metadata:
name: azure-credentials
namespace: default
type: Opaque
stringData:
identityId: <your-machine-identity-id>
---
# 2. Connection to the Infisical instance
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalConnection
metadata:
name: my-infisical-connection
namespace: default
spec:
address: https://app.infisical.com
---
# 3. Auth using Azure managed identity
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalAuth
metadata:
name: my-infisical-auth
namespace: default
spec:
infisicalConnectionRef:
name: my-infisical-connection
namespace: default
method: azure
azure:
identityIdRef:
name: azure-credentials
namespace: default
key: identityId
---
# 4. Sync secrets into a native Kubernetes Secret
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
namespace: default
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
syncOptions:
refreshInterval: 60s
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
```
```yaml complete-gcp-id-token-auth.yaml
# 1. Kubernetes secret holding the machine identity ID
apiVersion: v1
kind: Secret
metadata:
name: gcp-id-token-credentials
namespace: default
type: Opaque
stringData:
identityId: <your-machine-identity-id>
---
# 2. Connection to the Infisical instance
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalConnection
metadata:
name: my-infisical-connection
namespace: default
spec:
address: https://app.infisical.com
---
# 3. Auth using a GCP ID token
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalAuth
metadata:
name: my-infisical-auth
namespace: default
spec:
infisicalConnectionRef:
name: my-infisical-connection
namespace: default
method: gcp-id-token
gcpIdToken:
identityIdRef:
name: gcp-id-token-credentials
namespace: default
key: identityId
---
# 4. Sync secrets into a native Kubernetes Secret
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
namespace: default
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
syncOptions:
refreshInterval: 60s
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
```
<Note>
The `serviceAccountKeyFilePath` must point to a file that exists inside the **operator pod**. You will need to create a Kubernetes Secret with your GCP service account key and mount it as a volume in the operator Deployment (or via Helm values). See the [GCP IAM Auth](/documentation/platform/identities/gcp-auth) guide for details.
</Note>
```yaml complete-gcp-iam-auth.yaml
# 1. Kubernetes secret holding the machine identity ID
apiVersion: v1
kind: Secret
metadata:
name: gcp-iam-credentials
namespace: default
type: Opaque
stringData:
identityId: <your-machine-identity-id>
---
# 2. Connection to the Infisical instance
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalConnection
metadata:
name: my-infisical-connection
namespace: default
spec:
address: https://app.infisical.com
---
# 3. Auth using GCP IAM with a service account key
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalAuth
metadata:
name: my-infisical-auth
namespace: default
spec:
infisicalConnectionRef:
name: my-infisical-connection
namespace: default
method: gcp-iam
gcpIam:
identityIdRef:
name: gcp-iam-credentials
namespace: default
key: identityId
serviceAccountKeyFilePath: /path/to/service-account-key.json
---
# 4. Sync secrets into a native Kubernetes Secret
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
namespace: default
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
syncOptions:
refreshInterval: 60s
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
```
```yaml complete-ldap-auth.yaml
# 1. Kubernetes secret holding LDAP credentials and the machine identity ID
apiVersion: v1
kind: Secret
metadata:
name: ldap-credentials
namespace: default
type: Opaque
stringData:
identityId: <your-machine-identity-id>
username: <your-ldap-username>
password: <your-ldap-password>
---
# 2. Connection to the Infisical instance
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalConnection
metadata:
name: my-infisical-connection
namespace: default
spec:
address: https://app.infisical.com
---
# 3. Auth using LDAP
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalAuth
metadata:
name: my-infisical-auth
namespace: default
spec:
infisicalConnectionRef:
name: my-infisical-connection
namespace: default
method: ldap
ldap:
identityIdRef:
name: ldap-credentials
namespace: default
key: identityId
usernameRef:
name: ldap-credentials
namespace: default
key: username
passwordRef:
name: ldap-credentials
namespace: default
key: password
---
# 4. Sync secrets into a native Kubernetes Secret
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
namespace: default
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
syncOptions:
refreshInterval: 60s
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
```
| Field | Required | Description |
|---|---|---|
name | Yes | The name of the InfisicalAuth resource. |
namespace | Yes | The namespace of the InfisicalAuth resource. |
See the InfisicalAuth CRD documentation for details. </Accordion>
<Accordion title="syncOptions"> Controls the synchronization behavior.| Field | Required | Description |
|---|---|---|
refreshInterval | Yes | How often to resync (e.g. 60s, 5m, 1h). |
instantUpdates | No | When true, the operator receives real-time push updates from Infisical. Please note that this is an Enterprise feature. |
When multiple sources produce a secret with the same key, the first occurrence wins — sources listed earlier in the array take precedence over later ones. Direct secrets always take precedence over imported secrets, regardless of source order.
To access a secret that was dropped by the merge (e.g. a duplicate key under a different path or source), use the secretFrom template function to select it by its full path.
| Field | Required | Description |
|---|---|---|
projectId | No | The Infisical project ID. |
projectSlug | No | The Infisical project slug. |
environmentSlug | Yes | The environment slug (e.g. dev, staging, prod). |
secretPath | Yes | The path to the secrets. Root is /. |
tagSlugs | No | Filter secrets by tag slugs. |
recursive | No | Whether to recursively fetch secrets from sub-folders. Defaults to false. |
<Note>You have to provide either projectId or projectSlug. If none or both are set, the CRD validation will fail.</Note>
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /app
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /shared
recursive: true
tagSlugs:
- backend
| Field | Required | Description |
|---|---|---|
name | Yes | Name of the managed Kubernetes Secret or ConfigMap. |
namespace | Yes | Namespace of the managed Kubernetes Secret or ConfigMap. |
kind | Yes | The type of resource to create. Must be Secret or ConfigMap. |
secretType | No | Override the default Opaque secret type. Only applies when kind: Secret. When using a typed secret (e.g. kubernetes.io/tls, kubernetes.io/dockerconfigjson), you must use a template to produce the keys that Kubernetes requires for that type, otherwise the API server will reject the resource. |
creationPolicy | Yes | Owner sets a Kubernetes owner reference so the managed resource is automatically deleted by the garbage collector when the InfisicalStaticSecret is removed. Orphan leaves the managed resource in place. |
template | No | Optional templating configuration (see Templating below). |
metadata | No | Custom labels and annotations to set on the managed resource. When set, these values are used as-is and not merged with the InfisicalStaticSecret CRD metadata. |
targets:
- name: app-secrets
namespace: default
kind: Secret
creationPolicy: Owner
- name: app-config
namespace: default
kind: ConfigMap
creationPolicy: Orphan
metadata:
labels:
app: my-app
annotations:
description: "Synced from Infisical"
The operator provides flexible options for managing labels and annotations on managed Kubernetes Secrets and ConfigMaps.
<AccordionGroup> <Accordion title="Default behavior"> By default, the operator merges labels and annotations from the `InfisicalStaticSecret` resource into each managed Secret or ConfigMap that does not define target-level `metadata`.Conflict behavior:
- Existing labels and annotations that were not previously managed by the operator are preserved.
- Labels and annotations from the `InfisicalStaticSecret` resource take precedence when the same key already exists on the managed resource.
- Labels and annotations previously propagated by the operator are removed if they are removed from the `InfisicalStaticSecret` resource.
- Kubernetes system annotations and Infisical operator tracking annotations are preserved.
```yaml
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
labels:
label-to-be-passed-to-managed-secret: sample-value
annotations:
example.com/annotation-to-be-passed-to-managed-secret: "sample-value"
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
sources:
- projectId: <your-project-id>
environmentSlug: dev
secretPath: /
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
```
This creates a managed Secret with the inherited metadata:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: managed-secret
namespace: default
labels:
label-to-be-passed-to-managed-secret: sample-value
annotations:
example.com/annotation-to-be-passed-to-managed-secret: sample-value
secrets.infisical.com/version: W/"3f1-ZyOSsrCLGSkAhhCkY2USPu2ivRw"
type: Opaque
data: ...
```
- Target `metadata.labels` replaces the managed resource's labels.
- Target `metadata.annotations` replaces user-defined annotations on the managed resource.
- Kubernetes system annotations and the Infisical version annotation are preserved.
- Labels and annotations from the `InfisicalStaticSecret` resource are not propagated to that target.
- This lets you keep CRD-specific metadata separate from managed resource metadata.
<Tip>
To prevent any propagation while using target `metadata`, pass empty objects for labels and/or annotations:
```yaml
targets:
- name: managed-secret
namespace: default
kind: Secret
creationPolicy: Owner
metadata:
labels: {}
annotations: {}
```
</Tip>
```yaml
apiVersion: secrets.infisical.com/v1beta1
kind: InfisicalStaticSecret
metadata:
name: my-static-secret
labels:
managed-by: infisical-operator
annotations:
example.com/cr-specific: "metadata"
spec:
infisicalAuthRef:
name: my-infisical-auth
namespace: default
sources:
- projectId: <your-project-id>
environmentSlug: prod
secretPath: /
targets:
- name: managed-secret-with-custom-metadata
namespace: default
kind: Secret
creationPolicy: Owner
metadata:
labels:
app: my-application
environment: production
tier: backend
annotations:
secret.example.com/description: "Production database credentials"
secret.example.com/owner: "platform-team"
```
This creates a managed Secret with only the target metadata:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: managed-secret-with-custom-metadata
namespace: default
labels:
app: my-application
environment: production
tier: backend
annotations:
secret.example.com/description: "Production database credentials"
secret.example.com/owner: "platform-team"
type: Opaque
data: ...
```
kubectl apply -f infisical-static-secret.yaml
Verify the managed secret was created:
kubectl get secrets -n <namespace>
The managed Kubernetes Secret or ConfigMap works like any other native resource. You can reference it via envFrom, env, or volumes:
<Accordion title="env">
```yaml
env:
- name: SECRET_NAME
valueFrom:
secretKeyRef:
name: managed-secret
key: SOME_SECRET_KEY
```
</Accordion>
<Accordion title="volumes">
```yaml
volumes:
- name: secrets-volume
secret:
secretName: managed-secret
```
</Accordion>
</AccordionGroup>
<Accordion title="env">
```yaml
env:
- name: CONFIG_VALUE
valueFrom:
configMapKeyRef:
name: managed-configmap
key: SOME_CONFIG_KEY
```
</Accordion>
<Accordion title="volumes">
```yaml
volumes:
- name: config-volume
configMap:
name: managed-configmap
```
</Accordion>
</AccordionGroup>
Pods that consume a managed Secret or ConfigMap don't reload automatically when the underlying data changes. Without a restart, the workload may continue using stale values, especially when secrets are injected as environment variables.
To trigger a rolling restart when the managed resource updates, add the following annotation to the Deployment, StatefulSet, or DaemonSet that consumes it:
secrets.infisical.com/auto-reload: "true"
You can check the status of your InfisicalStaticSecret resource by inspecting its conditions:
kubectl get infisicalstaticsecret my-static-secret -o jsonpath='{.status.conditions}' | jq
When reconciliation is successful, the secrets.infisical.com/LastReconcileStatus condition will have Status: "True", Reason: "OK", and Message: "Reconciliation successful".
If reconciliation fails, Status will be "False", Reason will be set to Error, and Message will contain details about what went wrong.
The ObservedGeneration field indicates which generation of the resource spec the operator has last processed. If ObservedGeneration is less than metadata.generation, the operator has not yet reconciled the latest changes to the resource.