Skip to main content

Documentation Index

Fetch the complete documentation index at: https://infisical.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

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

infisical-static-secret.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

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.
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.
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.
sources:
  - projectId: <your-project-id>
    environmentSlug: dev
    secretPath: /app
  - projectId: <your-project-id>
    environmentSlug: dev
    secretPath: /shared
    recursive: true
    tagSlugs:
      - backend
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.
ConfigMaps are intended for non-sensitive data only. Use kind: Secret for sensitive values.
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"

Templating

Fetching secrets from Infisical as-is via the operator may not be enough. This is where templating functionality may be helpful. Using Go templates, you can format, combine, and create new key-value pairs from secrets fetched from Infisical before storing them as Kubernetes Secrets or ConfigMaps. When a template is set, only the keys defined in template.data are included in the output. When no template is set, all fetched secrets are included as-is. Each secret is available in the template context as .SECRET_KEY, which is an object with two accessors:
  • .Value: the secret value.
  • .SecretPath: the path of the secret in Infisical.

Key/value template map

targets:
  - name: my-app-config
    namespace: default
    kind: Secret
    creationPolicy: Owner
    template:
      engineVersion: v1
      data:
        DSN: "{{ .SECRET.Value }}.namespace:{{ .SECRET2.Value }}"
        ANOTHER_ONE: "{{ .SECRET3.Value }}"

Bulk string template with a loop

targets:
  - name: all-secrets
    namespace: default
    kind: Secret
    creationPolicy: Owner
    template:
      engineVersion: v1
      data: |
        {{- range $key, $secret := . }}
        {{ $key }}: "{{ $secret.Value }}"
        {{- end }}
To help transform your secrets further, the operator provides a set of built-in functions that you can use in your templates.

Available helper functions

The Infisical Secrets Operator exposes a wide range of helper functions to make it easier to work with secrets in Kubernetes.
Encodes a string to a base64-encoded string (e.g. hello world becomes aGVsbG8gd29ybGQ=).Signature
encodeBase64(plainString string) string
Template usage
template:
  data:
    ENCODED_SECRET: "{{ .MY_SECRET.Value | encodeBase64 }}"
Decodes a base64-encoded string back to its original value (e.g. aGVsbG8gd29ybGQ= becomes hello world).Signature
decodeBase64ToBytes(encodedString string) string
Template usage
template:
  data:
    DECODED_SECRET: "{{ .MY_BASE64_SECRET.Value | decodeBase64ToBytes }}"
Extracts all private keys from a PKCS#12 archive and returns them as PKCS#8 PEM-encoded blocks (-----BEGIN PRIVATE KEY-----...). The archive must not be password-protected — use pkcs12keyPass for password-protected archives.Signature
pkcs12key(input string) string
Template usage
template:
  data:
    tls.key: "{{ .TLS_CERT_PKCS12.Value | pkcs12key }}"
Same as pkcs12key, but uses the provided password to decrypt the PKCS#12 archive.Signature
pkcs12keyPass(password string, input string) string
Template usage
template:
  data:
    tls.key: '{{ pkcs12keyPass "my-password" .TLS_CERT_PKCS12.Value }}'
Extracts all certificates from a PKCS#12 archive and returns them as an ordered PEM chain (-----BEGIN CERTIFICATE-----...). Sort order: leaf → intermediate(s) → root. If disjunct or multiple leaf certs are provided, they are returned as-is. The archive must not be password-protected — use pkcs12certPass for password-protected archives.Signature
pkcs12cert(input string) string
Template usage
template:
  data:
    tls.crt: "{{ .TLS_CERT_PKCS12.Value | pkcs12cert }}"
Same as pkcs12cert, but uses the provided password to decrypt the PKCS#12 archive.Signature
pkcs12certPass(password string, input string) string
Template usage
template:
  data:
    tls.crt: '{{ pkcs12certPass "my-password" .TLS_CERT_PKCS12.Value }}'
Takes a PEM-encoded certificate and private key and creates a base64-encoded PKCS#12 archive. The output is not password-protected — use pemToPkcs12Pass to set a password.Signature
pemToPkcs12(cert string, key string) string
Template usage
template:
  data:
    keystore.p12: '{{ pemToPkcs12 .TLS_CERT.Value .TLS_KEY.Value }}'
Same as pemToPkcs12, but encrypts the PKCS#12 archive with the provided password.Signature
pemToPkcs12Pass(cert string, key string, password string) string
Template usage
template:
  data:
    keystore.p12: '{{ pemToPkcs12Pass .TLS_CERT.Value .TLS_KEY.Value "my-password" }}'
Takes a full PEM-encoded certificate chain (leaf + intermediates + root) and a private key, and creates a base64-encoded PKCS#12 archive that includes the entire chain. The output is not password-protected — use fullPemToPkcs12Pass to set a password.Signature
fullPemToPkcs12(cert string, key string) string
Template usage
template:
  data:
    keystore.p12: '{{ fullPemToPkcs12 .TLS_FULL_CHAIN.Value .TLS_KEY.Value }}'
Same as fullPemToPkcs12, but encrypts the PKCS#12 archive with the provided password.Signature
fullPemToPkcs12Pass(cert string, key string, password string) string
Template usage
template:
  data:
    keystore.p12: '{{ fullPemToPkcs12Pass .TLS_FULL_CHAIN.Value .TLS_KEY.Value "my-password" }}'
Filters PEM blocks by type from a bundle containing multiple PEM blocks (e.g. extract only CERTIFICATE or PRIVATE KEY blocks). Common PEM types: CERTIFICATE, PRIVATE KEY, PUBLIC KEY, RSA PRIVATE KEY.Signature
filterPEM(pemType string, input string) string
Template usage
template:
  data:
    ca.crt: '{{ filterPEM "CERTIFICATE" .TLS_BUNDLE.Value }}'
    tls.key: '{{ filterPEM "PRIVATE KEY" .TLS_BUNDLE.Value }}'
Filters PEM certificates by their position in a certificate chain. The chain is automatically ordered before filtering. Accepted types: leaf (end-entity certificate), intermediate (all intermediate CA certificates), root (root CA certificate). Returns an empty string if the requested type is not present in the chain.Signature
filterCertChain(certType string, input string) string
Template usage
template:
  data:
    tls.crt: '{{ filterCertChain "leaf" .TLS_CHAIN.Value }}'
    ca.crt: '{{ filterCertChain "root" .TLS_CHAIN.Value }}'
    intermediate.crt: '{{ filterCertChain "intermediate" .TLS_CHAIN.Value }}'
Takes a JSON-serialized JWK and returns a PEM block of type PUBLIC KEY containing the public key. Uses x509.MarshalPKIXPublicKey internally.Signature
jwkPublicKeyPem(jwkJson string) string
Template usage
template:
  data:
    public.pem: "{{ .MY_JWK.Value | jwkPublicKeyPem }}"
Takes a JSON-serialized JWK and returns a PEM block of type PRIVATE KEY containing the private key. Uses x509.MarshalPKCS8PrivateKey internally.Signature
jwkPrivateKeyPem(jwkJson string) string
Template usage
template:
  data:
    private.pem: "{{ .MY_JWK.Value | jwkPrivateKeyPem }}"
Marshals a value to a YAML string. Returns an empty string on marshal error.Signature
toYaml(v any) string
Template usage
template:
  data:
    config.yaml: "{{ .APP_CONFIG.Value | fromYaml | toYaml }}"
Parses a YAML string into a map[string]any, useful for extracting individual fields from a YAML-formatted secret (e.g. (fromYaml .DB_CONFIG.Value).host returns the host field).Signature
fromYaml(str string) map[string]any
Template usage
template:
  data:
    DB_HOST: '{{ (fromYaml .DB_CONFIG.Value).host }}'
    DB_PORT: '{{ (fromYaml .DB_CONFIG.Value).port }}'

Sprig functions

The Infisical Secrets Operator integrates with the Sprig library to provide additional helper functions.
We’ve removed expandEnv and env from the supported functions for security reasons.

Metadata propagation

The operator provides flexible options for managing labels and annotations on managed Kubernetes Secrets and ConfigMaps.
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.
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:
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: ...
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.
To prevent any propagation while using target metadata, pass empty objects for labels and/or annotations:
targets:
  - name: managed-secret
    namespace: default
    kind: Secret
    creationPolicy: Owner
    metadata:
      labels: {}
      annotations: {}
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:
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: ...

Applying the CRD

kubectl apply -f infisical-static-secret.yaml
Verify the managed secret was created:
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:
envFrom:
  - secretRef:
      name: managed-secret
env:
  - name: SECRET_NAME
    valueFrom:
      secretKeyRef:
        name: managed-secret
        key: SOME_SECRET_KEY
volumes:
  - name: secrets-volume
    secret:
      secretName: managed-secret

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:
secrets.infisical.com/auto-reload: "true"
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
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
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
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.

Troubleshooting

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.