Skip to content

Secrets

Secrets, encrypted or unencrypted, should not reside in Git and are best managed by a dedicated secret manager.

Navecd integrates well with the External Secrets Operator.

Example

infrastructure/eso.cue
package externalsecrets

import (
  "github.com/kharf/navecd/schema/component"
)

_name: "external-secrets"

ns: component.#Manifest & {
  apiVersion: "v1"
  kind: "Secret"
  metadata: name: _name
}

release: component.#HelmRelease & {
  dependencies: [
    ns.id,
  ]
  name:      _name
  namespace: ns.content.metadata.name
  chart: {
    name:    _name
    repoURL: "oci://ghcr.io/external-secrets/charts"
    version: "x.x.x"
  }
}
infrastructure/store.cue
package externalsecrets

import (
  "github.com/kharf/navecd/schema/component"
  // go get github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1
  // cue get go github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1
  "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
)

storeServiceAccount: component.#Manifest & {
  dependencies: [
    ns.id,
  ]
  content: {
    apiVersion: "v1"
    kind:       "ServiceAccount"
    metadata: {
      name:      "secret-store"
      namespace: ns.content.metadata.name
    }
  }
}

storeRole: component.#Manifest & {
  content: {
    apiVersion: "rbac.authorization.k8s.io/v1"
    kind:       "ClusterRole"
    metadata: {
      name: "secret-store"
    }
    rules: [{
      apiGroups: [""]
      resources: ["secrets"]
      verbs: [
        "get",
        "list",
        "watch",
      ]
    }, {
      apiGroups: ["authorization.k8s.io"]
      resources: ["selfsubjectrulesreviews"]
      verbs: ["create"]
    }]
  }
}

storeRoleBinding: component.#Manifest & {
  dependencies: [
    secretsNs.id,
    storeRole.id,
    storeServiceAccount.id,
  ]
  content: {
    apiVersion: "rbac.authorization.k8s.io/v1"
    kind:       "RoleBinding"
    metadata: {
      name:      "secret-store"
      namespace: secretsNs.content.metadata.name
    }
    roleRef: {
      apiGroup: "rbac.authorization.k8s.io"
      kind:     storeRole.content.kind
      name:     storeRole.content.metadata.name
    }
    subjects: [{
      kind:      storeServiceAccount.content.kind
      name:      storeServiceAccount.content.metadata.name
      namespace: storeServiceAccount.content.metadata.namespace
    }]
  }
}

store: component.#Manifest & {
  dependencies: [
    storeServiceAccount.id,
  ]
  content: v1beta1.#SecretStore & {
    apiVersion: "external-secrets.io/v1beta1"
    kind:       "SecretStore"
    metadata: {
      name:      "secret-store"
      namespace: ns.content.metadata.name
    }
    spec: provider: kubernetes: {
      remoteNamespace: "secrets"
      server: {
        caProvider: {
          type: "ConfigMap"
          name: "kube-root-ca.crt"
          key:  "ca.crt"
        }
      }
      auth: serviceAccount: name: storeServiceAccount.content.metadata.name
    }
  }
}

secrets: component.#Manifest & {
  dependencies: [
    store.id,
  ]
  content: v1beta1.#ExternalSecret & {
    apiVersion: "external-secrets.io/v1beta1"
    kind:       "ExternalSecret"
    metadata: {
      name:      "secrets"
      namespace: ns.content.metadata.name
    }
    spec: {
      refreshInterval: "1h"
      secretStoreRef: {
        kind: "SecretStore"
        name: store.content.metadata.name
      }
      target: {
        name: secretsNs.content.metadata.name
      }
      data: [{
        secretKey: "username"
        remoteRef: {
          key:      "database-credentials"
          property: "username"
        }
      }, {
      secretKey: "password"
      remoteRef: {
        key:      "database-credentials"
        property: "password"
      }
      }]
        }
    }
}

secretsNs: component.#Manifest & {
  content: {
    apiVersion: "v1"
    kind: "Secret"
    metadata: name: "secrets"
  } 
}