Skip to content

Latest commit

 

History

History
141 lines (117 loc) · 3.58 KB

README.md

File metadata and controls

141 lines (117 loc) · 3.58 KB

Vault OIDC SSH Certificate Action

This action uses GitHub's OIDC support to authenticate towards a HashiCorp Vault instance or an OpenBao instance, and to request a (short-lived) SSH client certificate from it.

Example Usage

jobs:
  deploy:
    permissions:
      contents: read
      id-token: write
    # ...
    steps:
      # ...
      - name: Generate SSH client certificate
        if: github.ref == 'refs/heads/main'
        id: ssh_cert
        uses: andreaso/vault-oidc-ssh-cert-action@v1
        with:
          vault_server: https://vault.example.com:8200
          jwt_audience: vault.example.com
          jwt_oidc_backend_path: github-oidc
          jwt_oidc_role: example-user
          ssh_backend_path: ssh-client-ca
          ssh_role: github-actions-example

      - name: Deploy site
        if: github.ref == 'refs/heads/main'
        run: >
          rsync -e "ssh -i '$SSH_KEY_PATH'"
          --verbose --recursive --delete-after --perms --chmod=D755,F644
          build/ [email protected]:/var/www/site/
        env:
          SSH_KEY_PATH: ${{ steps.ssh_cert.outputs.key_path }}

Do note that all client certification configuration is expected to happen on the Vault end, given that that is where all the limitations can be enforced.

Corresponding Configuration

HashiCorp Vault

resource "vault_jwt_auth_backend" "github" {
  path               = "github-oidc"
  oidc_discovery_url = "https://token.actions.githubusercontent.com"
  bound_issuer       = "https://token.actions.githubusercontent.com"
}

resource "vault_mount" "ssh_ca" {
  path        = "ssh-client-ca"
  type        = "ssh"
}

resource "vault_ssh_secret_backend_ca" "ssh_ca" {
  backend              = vault_mount.ssh_ca.path
  key_type             = "ed25519"
  generate_signing_key = true
}
resource "vault_ssh_secret_backend_role" "example" {
  name                    = "github-actions-example"
  backend                 = vault_mount.ssh_ca.path
  max_ttl                 = "900"
  key_type                = "ca"
  allow_user_certificates = true
  allow_host_certificates = false
  allowed_users           = "[email protected]"
  default_user            = "[email protected]"
  default_extensions      = {}

  allowed_user_key_config {
    type    = "ed25519"
    lengths = [0]
  }
}

data "vault_policy_document" "example" {
  rule {
    path         = "${vault_mount.ssh_ca.path}/sign/${vault_ssh_secret_backend_role.example.name}"
    capabilities = ["update"]
  }
}

resource "vault_policy" "example" {
  name   = "example-policy"
  policy = data.vault_policy_document.example.hcl
}

resource "vault_jwt_auth_backend_role" "example" {
  backend         = vault_jwt_auth_backend.github.path
  role_type       = "jwt"
  role_name       = "example-user"
  token_max_ttl   = "300"
  token_policies  = [vault_policy.example.name]
  user_claim      = "actor"
  bound_audiences = ["vault.example.com"]
  bound_claims    = {
    repository = "OWNER/REPO-NAME",
    ref        = "refs/heads/main",
  }
}
output "ssh_ca" {
  value = vault_ssh_secret_backend_ca.ssh_ca.public_key
}

OpenSSH

# /etc/ssh/sshd_config
# ...
TrustedUserCAKeys /etc/ssh/sshd_user_ca.pub
AuthorizedPrincipalsFile /etc/ssh/user_principals/%u
# /etc/ssh/sshd_user_ca.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
# /etc/ssh/user_principals/deployer
[email protected]