-
Notifications
You must be signed in to change notification settings - Fork 3
feat: add secure credential management with Vault #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
sabre1041
merged 2 commits into
redhat-cop:main
from
stevefulme1:feat/secure-credential-management
Apr 14, 2026
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,255 @@ | ||
| # Secure Credential Management | ||
|
|
||
| This document describes how the Ansible for OpenShift Virtualization Migration | ||
| manages sensitive credentials and the recommended practices for | ||
| keeping them secure. | ||
|
|
||
| ## Architecture Overview | ||
|
|
||
| The Ansible for OpenShift Virtualization Migration uses a layered approach to credential management: | ||
|
|
||
| 1. **Ansible Vault** — Encrypts sensitive variable files at rest so | ||
| credentials are never stored in plaintext in Git. | ||
| 2. **AAP Credential Types** — Stores and injects credentials at runtime | ||
| via Ansible Automation Platform's built-in credential management. | ||
| 3. **Kubernetes Secrets** — Stores credentials (API | ||
| tokens, service account keys) in OpenShift. | ||
| 4. **Environment Variable Injection** — AAP custom credential types | ||
| inject secrets as environment variables or extra vars into job | ||
| template execution. | ||
|
|
||
| ``` | ||
| ┌──────────────────────────────────────────────────┐ | ||
| │ Ansible Automation Platform │ | ||
| │ │ | ||
| │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ | ||
| │ │ Machine │ │ Source │ │ Custom │ │ | ||
| │ │ Creds │ │ Control │ │ Cred │ │ | ||
| │ │ (SSH keys) │ │ (Git) │ │ Types │ │ | ||
| │ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │ | ||
| │ │ │ │ │ | ||
| │ └───────────┬────┘───────────────┘ │ | ||
| │ │ │ | ||
| │ Injected at runtime │ | ||
| │ │ │ | ||
| │ ┌─────▼──────┐ │ | ||
| │ │ Job │ │ | ||
| │ │ Template │ │ | ||
| │ │ Execution │ │ | ||
| │ └────────────┘ │ | ||
| └──────────────────────────────────────────────────┘ | ||
| ``` | ||
|
|
||
| ## Credential Inventory | ||
|
|
||
| The following credentials are managed by the Ansible for OpenShift Virtualization Migration: | ||
|
|
||
| | Credential | Storage Method | Used By | | ||
| |---|---|---| | ||
| | Red Hat account (username/password) | AAP Credential / Vault | `bootstrap` role | | ||
| | OpenShift API token | Kubernetes Secret / AAP | `create_mf_aap_token`, all k8s tasks | | ||
| | Git repository (username/password or SSH key) | AAP Source Control Credential | `aap_seed` role, project sync | | ||
| | Container registry (host/username/password) | AAP Container Registry Credential | EE image pulls | | ||
| | Automation Hub tokens (certified + validated) | AAP Galaxy Credential | Collection sync | | ||
| | VMware vCenter (host/username/password) | AAP Custom Credential | `mtv_management` provider tasks | | ||
| | oVirt/RHV (host/username/password) | AAP Custom Credential | `mtv_management` provider tasks | | ||
| | VDDK registry (username/password) | AAP Custom Credential | `mtv_management` VDDK tasks | | ||
| | AAP admin (hostname/username/password/token) | AAP Credential | `aap_seed`, `bootstrap` | | ||
| | Machine SSH keys | AAP Machine Credential | `aap_machine_credentials` role | | ||
| | iDRAC (username/password) | AAP Custom Credential | Bootstrap bare-metal tasks | | ||
|
|
||
| > **Note:** This table reflects the credentials at time of writing and may not capture all credentials as the project evolves. Refer to the role defaults and AAP credential type definitions for the authoritative list. | ||
|
|
||
| ## Using Ansible Vault | ||
|
|
||
| Ansible Vault encrypts variable files so that sensitive values are never | ||
| stored in plaintext. | ||
|
|
||
| ### Initial Setup | ||
|
|
||
| 1. Copy the example vault file and populate it with real values: | ||
|
|
||
| ```bash | ||
| cp inventory.vault.yml.example inventory.vault.yml | ||
| ``` | ||
|
|
||
| 2. Edit `inventory.vault.yml` and replace placeholder values with | ||
| actual credentials. | ||
|
|
||
| 3. Encrypt the file: | ||
|
|
||
| ```bash | ||
| ansible-vault encrypt inventory.vault.yml | ||
| ``` | ||
|
|
||
| 4. Optionally, create a vault password file (excluded from Git by | ||
| `.gitignore`): | ||
|
|
||
| ```bash | ||
| echo 'your-vault-password' > .vault-password | ||
| chmod 600 .vault-password | ||
| ``` | ||
|
|
||
| ### Running Playbooks with Vault | ||
|
sabre1041 marked this conversation as resolved.
|
||
|
|
||
| With a password prompt: | ||
|
|
||
| ```bash | ||
| ansible-playbook -e @inventory.vault.yml \ | ||
| playbooks/bootstrap.yml --ask-vault-pass | ||
| ``` | ||
|
|
||
| With a password file: | ||
|
|
||
| ```bash | ||
| ansible-playbook -e @inventory.vault.yml \ | ||
| playbooks/bootstrap.yml --vault-password-file .vault-password | ||
| ``` | ||
|
|
||
| With ansible-navigator (password prompt): | ||
|
|
||
| ```bash | ||
| ansible-navigator run playbooks/bootstrap.yml \\ | ||
| -e @inventory.vault.yml --pae false \\ | ||
| -- --ask-vault-pass | ||
| ``` | ||
|
|
||
| With ansible-navigator (password file): | ||
|
|
||
| ```bash | ||
| ansible-navigator run playbooks/bootstrap.yml \\ | ||
| -e @inventory.vault.yml --pae false \\ | ||
| -- --vault-password-file .vault-password | ||
| ``` | ||
|
|
||
| ### Editing Encrypted Files | ||
|
|
||
| ```bash | ||
| ansible-vault edit inventory.vault.yml | ||
| ``` | ||
|
|
||
| ### Re-keying (Rotating the Vault Password) | ||
|
|
||
| ```bash | ||
| ansible-vault rekey inventory.vault.yml | ||
| ``` | ||
|
|
||
| ## AAP Custom Credential Types | ||
|
|
||
| The `aap_seed` role creates the following custom credential types in | ||
| AAP. These store secrets in AAP's encrypted database and inject them | ||
| into job template runs. | ||
|
|
||
| ### openshift_virtualization_migration_cac | ||
|
|
||
| Config-as-Code credential that stores Ansible for OpenShift Virtualization Migration configuration | ||
| including AAP settings, organization, and project details. | ||
|
|
||
| **Injected as extra vars:** | ||
|
|
||
| - `aap_version`, `aap_instance_name`, `aap_execution_environment` | ||
| - `aap_org_name`, `aap_namespace`, `aap_project`, `aap_inventory` | ||
| - `aap_job_template_extra_vars`, `migration_targets` | ||
|
|
||
| ### VMware Migration Target | ||
|
|
||
| Per-target VMware credentials for MTV provider configuration. | ||
|
|
||
| **Injected as extra vars and environment variables:** | ||
|
|
||
| - `VMWARE_HOST`, `VMWARE_USER`, `VMWARE_PASSWORD` (env) | ||
| - Target name, host, insecure SSL flag, VDDK image details (extra vars) | ||
|
|
||
| ### oVirt Migration Target | ||
|
|
||
| Per-target oVirt/RHV credentials for MTV provider configuration. | ||
|
|
||
| **Injected as extra vars and environment variables:** | ||
|
|
||
| - `OVIRT_HOSTNAME`, `OVIRT_USERNAME`, `OVIRT_PASSWORD` (env) | ||
| - Target name, host, insecure SSL flag (extra vars) | ||
|
|
||
| ## Secure Logging | ||
|
|
||
| All tasks that handle sensitive data use the `no_log` directive to | ||
| prevent credentials from appearing in Ansible output: | ||
|
|
||
| ```yaml | ||
| - name: Task with sensitive data | ||
| some_module: | ||
| password: "{{ secret_value }}" | ||
| no_log: "{{ secure_logging | default(true) }}" | ||
| ``` | ||
|
|
||
| The `secure_logging` variable defaults to `true`. Set it to `false` | ||
| only in development environments when debugging credential issues. | ||
|
|
||
| ## Access Control Recommendations | ||
|
|
||
| ### AAP Credentials | ||
|
|
||
| - Use AAP's role-based access control (RBAC) to restrict credential | ||
| access to specific teams and users. | ||
| - Grant the minimum permission level required: **Use** for job template | ||
| execution, **Admin** only for credential managers. | ||
| - Audit credential access regularly via AAP's activity stream. | ||
|
|
||
| ### Ansible Vault | ||
|
|
||
| - Use a unique vault password per environment (dev, staging, production). | ||
| - Store vault passwords in a secure location (e.g., a password manager | ||
| or secrets management service). | ||
| - Never commit vault password files to Git — they are excluded by | ||
| `.gitignore`. | ||
| - Rotate vault passwords periodically using `ansible-vault rekey`. | ||
|
|
||
| ### Kubernetes Secrets | ||
|
|
||
| - The `create_mf_aap_token` role creates a ServiceAccount with | ||
| `cluster-admin` privileges. Limit the scope if your environment | ||
| permits. | ||
| - Use OpenShift's RBAC to restrict access to the | ||
| `migration-factory-aap-sa-token` secret. | ||
| - Rotate service account tokens periodically. | ||
|
|
||
| ### Git Repositories | ||
|
|
||
| - Prefer SSH key authentication over username/password for Git | ||
| operations. | ||
| - Use deploy keys with read-only access where possible. | ||
| - The `.gitignore` excludes common secret file patterns (`secrets.yml`, | ||
| `*.vault.yml`, `vault-password*`, `.vault-password*`). | ||
| - Gitleaks is configured (`.gitleaks.toml`) and integrated into | ||
| pre-commit hooks and CI to detect accidental secret commits. | ||
|
|
||
| ## Migrating from Plaintext to Vault | ||
|
|
||
| If you have an existing `inventory.yml` with real credential values: | ||
|
|
||
| 1. Extract all sensitive values into `inventory.vault.yml`. | ||
| 2. Add the values to the vaulted `inventory.vault.yml` file. | ||
| 3. Replace the values in `inventory.yml` with variable references: | ||
|
|
||
| ```yaml | ||
| # inventory.yml (safe to commit) | ||
| rh_username: "{{ vault_rh_username }}" | ||
| rh_password: "{{ vault_rh_password }}" | ||
| ``` | ||
|
|
||
|
sabre1041 marked this conversation as resolved.
|
||
| ```yaml | ||
| # inventory.vault.yml (encrypted) | ||
| vault_rh_username: "actual-username" | ||
| vault_rh_password: "actual-password" | ||
| ``` | ||
|
|
||
| 4. Encrypt the vault file: | ||
|
|
||
| ```bash | ||
| ansible-vault encrypt inventory.vault.yml | ||
| ``` | ||
|
|
||
| 5. Verify no secrets remain in plaintext: | ||
|
|
||
| ```bash | ||
| gitleaks detect --config .gitleaks.toml --no-git | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| --- | ||
| # Sensitive Inventory Variables — Ansible Vault Encrypted | ||
| # | ||
| # This file contains all credential values that should be encrypted | ||
| # with Ansible Vault before use. Copy this file to inventory.vault.yml | ||
| # and encrypt it: | ||
| # | ||
| # cp inventory.vault.yml.example inventory.vault.yml | ||
| # # Edit inventory.vault.yml with real credential values | ||
| # ansible-vault encrypt inventory.vault.yml | ||
| # | ||
| # To edit an encrypted file: | ||
| # ansible-vault edit inventory.vault.yml | ||
| # | ||
| # To use with a playbook: | ||
|
sabre1041 marked this conversation as resolved.
|
||
| # ansible-playbook -e @inventory.vault.yml playbooks/bootstrap.yml --ask-vault-pass | ||
| # | ||
| # Or with a vault password file: | ||
| # ansible-playbook -e @inventory.vault.yml playbooks/bootstrap.yml --vault-password-file .vault-password | ||
| # | ||
| # With ansible-navigator: | ||
| # ansible-navigator run playbooks/bootstrap.yml \ | ||
| # -e @inventory.vault.yml --pae false \ | ||
| # -- --ask-vault-pass | ||
| # | ||
| # IMPORTANT: Never commit this file unencrypted. The .gitignore is | ||
| # configured to exclude *.vault.yml and vault-password* files. | ||
|
|
||
| # Red Hat Account | ||
| rh_username: "" | ||
| rh_password: "" | ||
|
|
||
| # Container Registry | ||
| container_host: "" | ||
| container_username: "" | ||
| container_password: "" | ||
|
|
||
| # Git Credentials | ||
| git_username: "" | ||
| git_password: "" | ||
| # git_ssh_private_key: | | ||
| # -----BEGIN OPENSSH PRIVATE KEY----- | ||
| # ... | ||
| # -----END OPENSSH PRIVATE KEY----- | ||
| # git_ssh_key_passphrase: "" | ||
|
|
||
| # Automation Hub Tokens | ||
| automation_hub_certified_token: "" | ||
| automation_hub_validated_token: "" | ||
|
|
||
| # OpenShift Cluster Credentials (Hub) | ||
| # Use ONE of the following authentication methods: | ||
| # hub_openshift_username: "" | ||
| # hub_openshift_password: "" | ||
| # hub_openshift_temporary_api_key: "" | ||
| # hub_openshift_api_key: "" | ||
|
|
||
| # OpenShift Cluster Credentials (Spoke) | ||
| # Use ONE of the following authentication methods: | ||
| # spoke_openshift_username: "" | ||
| # spoke_openshift_password: "" | ||
| # spoke_openshift_temporary_api_key: "" | ||
| # spoke_openshift_api_key: "" | ||
|
|
||
| # Migration Target Credentials | ||
| # vmware_username: "" | ||
| # vmware_password: "" | ||
| # ovirt_username: "" | ||
| # ovirt_password: "" | ||
|
|
||
| # VDDK Registry Credentials | ||
| # vddk_registry_username: "" | ||
| # vddk_registry_password: "" | ||
| ... | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.