Claude-skill-registry aap-vault-ssh
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/aap-vault-ssh" ~/.claude/skills/majiayu000-claude-skill-registry-aap-vault-ssh && rm -rf "$T"
manifest:
skills/data/aap-vault-ssh/SKILL.mdsource content
AAP + Vault SSH Integration
Dynamically signed SSH credentials replacing static key management.
Architecture
AAP Job → AppRole Auth → Vault SSH CA → Signed Certificate → Target Host
- AAP authenticates to Vault via AppRole
- AAP credential plugin submits SSH key for signing
- Vault SSH CA signs certificate (2hr TTL)
- AAP uses signed cert for SSH access
Quick Start
1. Vault Configuration (Terraform)
# Enable SSH secrets engine resource "vault_mount" "ssh" { path = "ssh" type = "ssh" } resource "vault_ssh_secret_backend_ca" "ssh" { backend = vault_mount.ssh.path generate_signing_key = true } # AppRole for AAP resource "vault_approle_auth_backend_role" "aap" { backend = "approle" role_name = var.tenant token_policies = ["aap-ssh"] } # SSH signing role resource "vault_ssh_secret_backend_role" "aap" { backend = vault_mount.ssh.path name = var.tenant key_type = "ca" allow_user_certificates = true default_user = "aap" allowed_users = "aap,ansible" ttl = "7200" default_extensions = { "permit-pty" = "" } }
Full Terraform config: See references/vault-config.md
2. AAP Credential Setup (Ansible)
# Vault SSH credential - name: Create Vault SSH Credential ansible.controller.credential: name: "vault_ssh_{{ tenant }}" credential_type: "HashiCorp Vault Signed SSH" inputs: url: "{{ vault_url }}" role_id: "{{ role_id }}" secret_id: "{{ secret_id }}" default_auth_path: "approle" # Machine credential linked to Vault - name: Create Machine Credential ansible.controller.credential: name: "machine_{{ tenant }}" credential_type: "Machine" inputs: username: "aap" register: machine_cred - name: Link to Vault Source ansible.controller.credential_input_source: input_field_name: "ssh_public_key_data" target_credential: "{{ machine_cred.id }}" source_credential: "vault_ssh_{{ tenant }}" metadata: role: "{{ tenant }}" secret_path: "ssh"
Full AAP config: See references/aap-config.md
3. Golden Image (Packer + Ansible)
Target hosts must trust Vault's SSH CA:
- name: Download Vault SSH CA ansible.builtin.get_url: url: "{{ vault_url }}/v1/ssh/public_key" headers: X-Vault-Namespace: "{{ vault_namespace }}" dest: /etc/ssh/trusted-user-ca-keys.pem - name: Configure SSH CA Trust ansible.builtin.lineinfile: path: /etc/ssh/sshd_config line: "TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem" notify: Restart SSH
Full image config: See references/golden-image.md
Multi-Tenancy
Map tenants across both platforms:
| AAP | Vault |
|---|---|
| Organization | Namespace |
| Credential | AppRole + SSH Role |
| Team | Entity/Group |
Policy templating for dynamic paths:
path "ssh/sign/{{identity.entity.name}}" { capabilities = ["read", "update"] }
Credential Rotation
Self-Rotation (Recommended)
AAP job rotates its own secret_id daily:
# Vault policy allowing self-rotation path "auth/approle/role/{{ tenant }}/secret-id" { capabilities = ["update"] }
Schedule AAP job template to run rotation playbook.
Troubleshooting
| Issue | Check |
|---|---|
| Auth failure | Verify role_id/secret_id, check namespace |
| Signing failure | Verify allowed_users includes target user |
| SSH rejected | Verify TrustedUserCAKeys on target, check CA fingerprint |
| Certificate expired | Check TTL settings (default 2hr) |
References
- references/vault-config.md - Complete Terraform for Vault SSH + AppRole
- references/aap-config.md - Complete Ansible for AAP credentials
- references/golden-image.md - Packer/Ansible for target host images