Skip to content

Conversation

@seunghun1ee
Copy link
Member

No description provided.

@seunghun1ee seunghun1ee self-assigned this Jan 9, 2026
@gemini-code-assist
Copy link

Summary of Changes

Hello @seunghun1ee, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust and automated solution for migrating existing HashiCorp Vault deployments to OpenBao using Ansible. It provides a structured approach to handle both single-node and High Availability Vault environments, ensuring that critical data, configurations, and TLS settings are seamlessly transitioned. The changes focus on orchestrating the storage backend migration, deploying OpenBao, and managing its lifecycle, thereby streamlining the process of adopting OpenBao.

Highlights

  • New Ansible Playbook for HA Migration: Introduced playbooks/ha_vault_bao_migration.yml, a dedicated Ansible playbook designed to orchestrate the migration of High Availability (HA) Vault clusters to OpenBao, ensuring a smooth transition for multi-node setups.
  • Comprehensive Migration Role: Added a new Ansible role roles/vault_bao_migration/ which encapsulates all necessary tasks for migrating from Vault to OpenBao. This role includes prerequisites, storage backend migration (from Consul to Raft), and specific logic for both single-node and HA migrations.
  • Storage Backend Migration to Raft: Implemented tasks within roles/vault_bao_migration/tasks/raft.yml to handle the migration of Vault's storage backend from Consul to Raft, including snapshotting Consul data, templating migration configurations, and restarting Vault with the new Raft backend.
  • OpenBao Deployment and Unsealing: Integrated the deployment of OpenBao instances using the stackhpc.hashicorp.openbao role and automated the unsealing process, including temporary unsealing for snapshot restoration and final unsealing, ensuring OpenBao is operational post-migration.
  • TLS Certificate and CA Copying: Added steps to automatically copy existing TLS keys, certificates, and CA files from the Vault configuration directory to the OpenBao configuration directory, preserving secure communication settings during the migration.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive Ansible role and playbook for migrating from HashiCorp Vault to OpenBao. The separation of logic for single-node and HA migrations is well-designed. However, the review identified several significant issues that need to be addressed. There is a critical logic flaw in the HA migration playbook concerning how new OpenBao nodes join the cluster, which will cause the migration to fail for followers. Additionally, there are multiple instances of unreliable pauses instead of robust polling, insecure file permissions, and inconsistencies in configuration variables. The provided feedback includes specific code suggestions and recommendations to fix these issues, improve reliability, and enhance the security of the migration process.

Comment on lines 102 to 103
openbao_raft_leaders:
- "{{ (new_leader_api_addr_query.json.leader_address if inventory_hostname == vault_raft_leader else vault_leader_api_addr) | urlsplit('hostname') }}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The logic for setting openbao_raft_leaders is incorrect for follower nodes. During the HA migration, followers are migrated first. This logic incorrectly makes them try to join the old Vault leader (vault_leader_api_addr) instead of forming a new OpenBao cluster. The first migrated follower should initialize the new OpenBao cluster, and all subsequent nodes should join it.

A more robust approach is to designate the first host in the ordered_vault_hosts group as the seed for the new OpenBao cluster. All other nodes will then join this seed node.

        openbao_raft_leaders: "{{ [groups['ordered_vault_hosts'][0]] if inventory_hostname != groups['ordered_vault_hosts'][0] else [] }}"

Comment on lines 73 to 74
ansible.builtin.wait_for:
timeout: 10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using wait_for with only a timeout creates an unreliable pause. A fixed delay may not be sufficient for a new leader to be elected in all environments. This is especially problematic in the context of this playbook where the step-down is executed on the last Vault node, meaning there are no other nodes to elect as a new leader. This part of the logic seems flawed and should be re-evaluated. If a pause is truly needed, ansible.builtin.pause is more explicit, but a polling mechanism that waits for a specific condition is always more robust.


openbao_protocol: "{{ 'https' if openbao_tls_key and openbao_tls_cert else 'http' }}"

openbao_api_addr: "{{ openbao_bind_addr ~ ':' ~ openbao_api_port }}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The openbao_api_addr default value is missing the protocol (http:// or https://). The OpenBao api_addr configuration parameter requires a full URL, including the protocol. This is inconsistent with the vault_api_addr definition in this same file and the documentation in the README, which specifies 'Full URL including protocol and port'.

openbao_api_addr: "{{ openbao_protocol }}://{{ openbao_bind_addr }}:{{ openbao_api_port }}"

ansible.builtin.file:
path: "{{ vault_staging_dir_path }}"
state: directory
mode: '0777'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Setting directory permissions to 0777 is insecure as it grants read, write, and execute permissions to everyone. The permissions for this staging directory should be more restrictive. Please use a more secure mode like 0750 or 0755 that follows the principle of least privilege.

    mode: '0755'

Comment on lines +78 to +81
ansible.builtin.wait_for:
timeout: 10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using wait_for with only a timeout creates an unreliable pause. After restoring a snapshot, OpenBao will restart and become sealed. Instead of a fixed pause, you should poll the /v1/sys/seal-status endpoint until the sealed status is true. This reliably indicates that the restore process is complete and the instance is ready to be unsealed with its original keys.

Comment on lines 52 to 54
1. Print to Ansible log output (`openbao_log_keys`)
1. Set a `openbao_keys` fact (`openbao_set_keys_fact`)
1. Write to a file (`openbao_write_keys_file`)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The numbered list is using 1. for all items. For clarity and correctness in Markdown, it should be an incrementing list (1., 2., 3.).

Suggested change
1. Print to Ansible log output (`openbao_log_keys`)
1. Set a `openbao_keys` fact (`openbao_set_keys_fact`)
1. Write to a file (`openbao_write_keys_file`)
1. Print to Ansible log output (`openbao_log_keys`)
2. Set a `openbao_keys` fact (`openbao_set_keys_fact`)
3. Write to a file (`openbao_write_keys_file`)

tasks:
- name: Enable bao secrets engines
hashivault_secret_engine:
url: "https://vault.example.com:8200"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The example URL https://vault.example.com:8200 could be confusing in a playbook for OpenBao post-deployment configuration. To avoid ambiguity, consider changing vault.example.com to something that more clearly represents OpenBao, such as bao.example.com.

Suggested change
url: "https://vault.example.com:8200"
url: "https://bao.example.com:8200"

Comment on lines 116 to 132
- name: Check the number of the raft peers
ansible.builtin.shell:
cmd: >
docker exec -e VAULT_TOKEN=$VAULT_TOKEN -e VAULT_ADDR=$VAULT_ADDR
{% if vault_tls_ca != "" %} -e VAULT_CAPATH=$VAULT_CAPATH {% endif %}
{{ vault_docker_name }}
vault operator raft list-peers -format=json | jq -r '.data.config.servers | length'
register: vault_raft_peer_length
environment:
VAULT_ADDR: "{{ vault_api_addr }}"
VAULT_TOKEN: "{{ vault_root_token }}"
VAULT_CAPATH: "{{ '/vault/config/' + vault_tls_ca if vault_tls_ca != '' else omit }}"
changed_when: false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using ansible.builtin.shell with jq introduces an external dependency on jq and can be less robust than using Ansible's built-in capabilities. You can achieve the same result by using the community.docker.docker_container_exec module to get the raw JSON output and then processing it with Ansible's from_json and length filters. This approach is more idiomatic to Ansible and removes the external dependency.

Comment on lines +53 to +56
owner_id: 100
group_id: 1000

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Hardcoding the owner_id and group_id is brittle, as these numeric IDs can vary across systems. If possible, use user and group names (e.g., openbao). If numeric IDs are necessary for this module, consider defining them as variables in defaults/main.yml to make them more manageable and easier to override.

Comment on lines 81 to 85
- name: Unseal OpenBao
ansible.builtin.import_role:
name: stackhpc.hashicorp.vault_unseal
vars:
vault_api_addr: "{{ openbao_api_addr }}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This task to unseal OpenBao implicitly relies on the vault_unseal_keys variable being populated with the original Vault unseal keys. This is not obvious from the playbook and can lead to failures if the variable is not set correctly by the user. It would be good practice to:

  1. Add a check to ensure vault_unseal_keys is defined and not empty before attempting to unseal.
  2. Document this requirement clearly in the role's README.md file.

@seunghun1ee seunghun1ee force-pushed the vault-bao-migration branch 3 times, most recently from dc56f29 to a8a4561 Compare January 12, 2026 16:11
Since ha_migration.yml is a separate playbook, migration_* variables
from vault_bao_migration role may not be defined when the playbook is
being used.
Added default values to make the playbook safe to run without optional
variables.
@seunghun1ee seunghun1ee force-pushed the vault-bao-migration branch 12 times, most recently from b145f17 to 172a03e Compare January 16, 2026 14:27
@seunghun1ee seunghun1ee force-pushed the vault-bao-migration branch 2 times, most recently from 00d6d48 to 17f27f2 Compare January 16, 2026 15:15
This option needs to be explictly set when using integrated storage
backend (Raft) from Vault 1.20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants