To secure store secrets used primarily for managed by ArgoCD kubernetes clusters with use Hashicorp Vault.

Vault is installed with ArgoCD in cicd k8s cluster with a helm chart.
https://github.com/SafiBank/SaFiMono/blob/main/devops/argocd/environments/cicd/vault/values.yaml

vault:
  persistence:
    enabled: true
    hostPath: "/vault/file"
    size: 2Gi
  
  ingress:
    enabled: true
    hosts:
      - vault.cicd.safibank.online
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
      traefik.ingress.kubernetes.io/router.tls: "true"
      traefik.ingress.kubernetes.io/router.entrypoints: websecure
    tls:
      - secretName: vault.cicd.safibank.online-tls
        hosts:
          - vault.cicd.safibank.online
        

  vault:
    externalConfig:
      policies:
        - name:  argocd
          rules: |-
            path "secret/data/*" {
              capabilities = ["read","list"]
            }
      auth:
        - type: kubernetes
          roles:
            - name: argocd
              bound_service_account_names: 
                - argocd-repo-server
              bound_service_account_namespaces: 
                - argocd
              policies: 
                - argocd
              ttl: 1h

    config:
      listener:
        tcp:
          address: "[::]:8200"
          tls_disable: true

      ui: true
      api_addr: http://localhost:8200

  unsealer:
    image:
      repository: ghcr.io/banzaicloud/bank-vaults
      pullPolicy: IfNotPresent
    args:
      [
        "--mode",
        "k8s",
        "--k8s-secret-namespace",
        "vault",
        "--k8s-secret-name",
        "bank-vaults",
      ]

In values we specify external policy and auth type for argocd-vault-replacer. Secrets are stored in persistent volume inside cluster.

Root token can’t be specified and is generated during first start as well as unseal keys and can be viewed in bank-vaults secret in kubernetes.

Policies for users and Okta auth type are configured with terraform.

locals {
  vault_admin_groups = [
    "DevOps"
  ]
  vault_viewer_groups = [
    "Developers"
  ]
  vault_label = "vault-cicd"
}

data "okta_group" "source_okta_vault_admin_group" {
  for_each = toset(local.vault_admin_groups)
  name     = each.value
}

data "okta_group" "source_okta_vault_viewer_group" {
  for_each = toset(local.vault_viewer_groups)
  name     = each.value
}

resource "okta_group" "vault_admin" {
  name        = "${local.vault_label}-admin"
  description = "Group of users with admin permissions to the ${local.vault_label}"
  skip_users  = true
}

resource "okta_group" "vault_viewer" {
  name        = "${local.vault_label}-viewer"
  description = "Group of users with read permissons to the ${local.vault_label}"
  skip_users  = true
}

resource "okta_group_rule" "vault_admin_group_rule" {
  for_each          = toset(local.vault_admin_groups)
  name              = "${local.vault_label}_admin_${index(local.vault_admin_groups, each.key)}"
  expression_value  = "isMemberOfGroup(\"${data.okta_group.source_okta_vault_admin_group[each.key].id}\")"
  group_assignments = [okta_group.vault_admin.id]
  status            = "ACTIVE"
}

resource "okta_group_rule" "vault_viewer_group_rule" {
  for_each          = toset(local.vault_viewer_groups)
  name              = "${local.vault_label}_viewer_${index(local.vault_viewer_groups, each.key)}"
  expression_value  = "isMemberOfGroup(\"${data.okta_group.source_okta_vault_viewer_group[each.key].id}\")"
  group_assignments = [okta_group.vault_viewer.id]
  status            = "ACTIVE"
}

resource "vault_okta_auth_backend" "okta" {
  description  = "Okta"
  organization = "safibank"
  token        = data.vault_generic_secret.okta.data["api_token"]
}

resource "vault_okta_auth_backend_group" "vault_admin" {
  path       = vault_okta_auth_backend.okta.path
  group_name = okta_group.vault_admin.name
  policies   = [vault_policy.vault_admin.name]
}

resource "vault_okta_auth_backend_group" "vault_viewer" {
  path       = vault_okta_auth_backend.okta.path
  group_name = okta_group.vault_viewer.name
  policies   = [vault_policy.vault_viewer.name]
}

resource "vault_policy" "vault_admin" {
  name   = "admin-policy"
  policy = file("${path.module}/vault-policies/admin.hcl")
}

resource "vault_policy" "vault_viewer" {
  name   = "viewer-policy"
  policy = file("${path.module}/vault-policies/viewer.hcl")
}

Policies

admin.hcl

# Read system health check
path "sys/health" { 
  capabilities = ["read", "sudo"]
}
# Create and manage ACL policies broadly across Vault
# List existing policies
path "sys/policies/acl" {
  capabilities = ["list"]
}
# Create and manage ACL policies
path "sys/policies/acl/*" {
   capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Enable and manage authentication methods broadly across Vault
# Manage auth methods broadly across Vault
path "auth/*" {
   capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Create, update, and delete auth methods
path "sys/auth/*" {
   capabilities = ["create", "update", "delete", "sudo"]
}
# List auth methods
path "sys/auth" {
  capabilities = ["read"]
}
# Enable and manage the key/value secrets engine at `secret/` path
# List, create, update, and delete key/value secrets
path "secret/*" {
   capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Manage secrets engines
path "sys/mounts/*" {
   capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# List existing secrets engines
path "sys/mounts" {
  capabilities = ["read"]
}

viewer.hcl

# Read permission on the k/v secrets
path "/secret/*" {
    capabilities = ["list"]
}
path "secret/data/dev/apps*" {
    capabilities = ["read", "list"]
}
path "secret/data/stage/apps*" {
    capabilities = ["read", "list"]
}
path "secret/data/brave/apps*" {
    capabilities = ["read", "list"]
}