Back to Infisical

Using the InfisicalStaticSecret CRD

docs/integrations/platforms/kubernetes/infisical-static-secret-crd.mdx

0.160.919.4 KB
Original Source

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.

Prerequisites

Before creating an InfisicalStaticSecret, you need:

  1. An InfisicalConnection resource configured with your Infisical host and TLS settings.
  2. An InfisicalAuth resource configured with your machine identity authentication method.

Example

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

  syncOptions:
    refreshInterval: 60s
    instantUpdates: false

  sources:
    - projectId: <your-project-id>
      environmentSlug: dev
      secretPath: /

  targets:
    - name: managed-secret
      namespace: default
      kind: Secret
      creationPolicy: Owner

CRD properties

<Accordion title="infisicalAuthRef"> A reference to the `InfisicalAuth` resource that defines how to authenticate with Infisical. The connection to the Infisical instance is resolved through the `InfisicalAuth` resource's `infisicalConnectionRef` field.
FieldRequiredDescription
nameYesThe name of the InfisicalAuth resource.
namespaceYesThe namespace of the InfisicalAuth resource.

See the InfisicalAuth CRD documentation for details. </Accordion>

<Accordion title="syncOptions"> Controls the synchronization behavior.
FieldRequiredDescription
refreshIntervalYesHow often to resync (e.g. 60s, 5m, 1h).
instantUpdatesNoWhen true, the operator receives real-time push updates from Infisical. Please note that this is an Enterprise feature.
</Accordion> <Accordion title="sources"> An array of secret sources to fetch from Infisical. All secrets from all sources are merged and made available to every target.

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.

FieldRequiredDescription
projectIdYesThe Infisical project ID.
environmentSlugYesThe environment slug (e.g. dev, staging, prod).
secretPathYesThe path to the secrets. Root is /.
tagSlugsNoFilter secrets by tag slugs.
recursiveNoWhether to recursively fetch secrets from sub-folders. Defaults to false.
yaml
sources:
  - projectId: <your-project-id>
    environmentSlug: dev
    secretPath: /app
  - projectId: <your-project-id>
    environmentSlug: dev
    secretPath: /shared
    recursive: true
    tagSlugs:
      - backend
</Accordion> <Accordion title="targets"> An array of Kubernetes Secrets or ConfigMaps to create/update with the fetched secrets.
FieldRequiredDescription
nameYesName of the managed Kubernetes Secret or ConfigMap.
namespaceYesNamespace of the managed Kubernetes Secret or ConfigMap.
kindYesThe type of resource to create. Must be Secret or ConfigMap.
secretTypeNoOverride 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.
creationPolicyYesOwner 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.
templateNoOptional templating configuration (see Templating below).
metadataNoCustom 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.
<Warning> ConfigMaps are intended for non-sensitive data only. Use `kind: Secret` for sensitive values. </Warning>
yaml
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"
</Accordion> <KubernetesOperatorTemplating />

Metadata propagation

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: ...
```
</Accordion> <Accordion title="Custom target metadata"> When you specify `metadata` on a target, those labels and annotations are used exclusively for that managed resource:
- 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: ...
```
</Accordion> </AccordionGroup>

Applying the CRD

bash
kubectl apply -f infisical-static-secret.yaml

Verify the managed secret was created:

bash
kubectl get secrets -n <namespace>

Using the managed resource in your deployment

The managed Kubernetes Secret or ConfigMap works like any other native resource. You can reference it via envFrom, env, or volumes:

<Tabs> <Tab title="Secret"> <AccordionGroup> <Accordion title="envFrom"> ```yaml envFrom: - secretRef: name: managed-secret ``` </Accordion>
  <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>
</Tab> <Tab title="ConfigMap"> <AccordionGroup> <Accordion title="envFrom"> ```yaml envFrom: - configMapRef: name: managed-configmap ``` </Accordion>
  <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>
</Tab> </Tabs>

Automatic redeployment

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:

yaml
secrets.infisical.com/auto-reload: "true"
<AccordionGroup> <Accordion title="Deployment example"> <Tabs> <Tab title="Secret"> ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx annotations: secrets.infisical.com/auto-reload: "true" spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 envFrom: - secretRef: name: managed-secret ports: - containerPort: 80 ``` </Tab> <Tab title="ConfigMap"> ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: app-deployment labels: app: app annotations: secrets.infisical.com/auto-reload: "true" spec: replicas: 1 selector: matchLabels: app: app template: metadata: labels: app: app spec: containers: - name: app image: mycompany/app:latest envFrom: - configMapRef: name: managed-configmap ports: - containerPort: 80 ``` </Tab> </Tabs> </Accordion> <Accordion title="DaemonSet example"> <Tabs> <Tab title="Secret"> ```yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: log-agent labels: app: log-agent annotations: secrets.infisical.com/auto-reload: "true" spec: selector: matchLabels: app: log-agent template: metadata: labels: app: log-agent spec: containers: - name: log-agent image: mycompany/log-agent:latest envFrom: - secretRef: name: managed-secret volumeMounts: - name: secrets-volume mountPath: /etc/secrets readOnly: true volumes: - name: secrets-volume secret: secretName: managed-secret ``` </Tab> <Tab title="ConfigMap"> ```yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: log-agent labels: app: log-agent annotations: secrets.infisical.com/auto-reload: "true" spec: selector: matchLabels: app: log-agent template: metadata: labels: app: log-agent spec: containers: - name: log-agent image: mycompany/log-agent:latest envFrom: - configMapRef: name: managed-configmap volumeMounts: - name: config-volume mountPath: /etc/config readOnly: true volumes: - name: config-volume configMap: name: managed-configmap ``` </Tab> </Tabs> </Accordion> <Accordion title="StatefulSet example"> <Tabs> <Tab title="Secret"> ```yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: db-worker labels: app: db-worker annotations: secrets.infisical.com/auto-reload: "true" spec: selector: matchLabels: app: db-worker serviceName: "db-worker" replicas: 2 template: metadata: labels: app: db-worker spec: containers: - name: db-worker image: mycompany/db-worker:stable env: - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: managed-secret key: DB_PASSWORD ports: - containerPort: 5432 ``` </Tab> <Tab title="ConfigMap"> ```yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: db-worker labels: app: db-worker annotations: secrets.infisical.com/auto-reload: "true" spec: selector: matchLabels: app: db-worker serviceName: "db-worker" replicas: 2 template: metadata: labels: app: db-worker spec: containers: - name: db-worker image: mycompany/db-worker:stable env: - name: DATABASE_HOST valueFrom: configMapKeyRef: name: managed-configmap key: DATABASE_HOST ports: - containerPort: 5432 ``` </Tab> </Tabs> </Accordion> </AccordionGroup> <Info> When a managed Secret or ConfigMap is updated, the operator checks for any Deployments, DaemonSets, or StatefulSets that consume the updated resource and have the `secrets.infisical.com/auto-reload: "true"` annotation. For each matching workload, the operator triggers a rolling restart so the pods pick up the latest values. </Info>

Troubleshooting

You can check the status of your InfisicalStaticSecret resource by inspecting its conditions:

bash
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.