Important
I'm sure that many aspects of this repository can be done in a better, more intelligent way. If you have suggestions or enhancements, please feel free to open a PR!
Tested with: Ansible v2.18.4 & macOS Sequoia 15
- 🔍 Overview
- 📝 Prerequisites
- 🚀 New System Bootstrap
- 📐 Bootstrap Execution Flow
- 🖥️ Bootstrap Script Usage
- 🖥️ Ansible Playbook Usage
- 🛡️ Security
- ⚙️ Customization
- 🐞 Issues / 📝 TODOs
- 🤝 Contributing
- 🔗 Connect
- 🧑💻 About Me
This is a Bash wrapper that uses a set of Ansible roles, to automate the macOS package installation and configuration of various applications, dependencies, plugins, fonts, and system settings.
While this setup is customized to my specific needs, I hope that parts of the code can be helpful or inspiring to others as well.
If you plan to adapt and use the bootstrap wrapper in its entirety, please ensure you have the following prerequisites in place:
- An active Bitwarden Account
- An already configured,encrypted and initiated Chezmoi repository
- An already configured and encrypted Dotbot repository
- An already configured and encrypted repository that keeps GPG,SSH and other relevant keys (or a path to your GPG keys but you need to adapt the relevant task)
Have a look at this post, explaining why I'm using both Chezmoi and Dotbot dotfile managers.
If the prerequisites feel overwhelming or unnecessary, you can skip ahead to the Ansible Playbook Usage section.
bootstrap.sh prepares the system by installing essential tools, such as Homebrew, Ansible, Bitwarden CLI, Ente Auth, Transcrypt, iTerm2 etc, required by the Ansible roles.
It also installs Ultimate Vimrc and oh-my-zsh including relevant themes and useful plugins.
Ansible roles then handle package installation, global settings configuration,font installation, gpg key importing and dotfile initialization, using both Chezmoi (for templated dotfiles) and Dotbot (for standard dotfiles). This post explains why I'm using two dotfile managers.
./bootstrap.sh --help # Show help message
./bootstrap.sh --install-packages # Install prerequisite packages
./bootstrap.sh --tags "brew,krew" # Run with specific tags
./bootstrap.sh --tags "cz" --ask-vault-pass # Use vault password for roles that are using encrypted files.- As you can also see from the Execution Flow diagramabove, first step in case of a fresh setup, is to install all relevant packages. Open the Terminal app and execute:
/bootstrap.sh --install-packagesTip
I have seen weird behaviour when executing the wrapper from Terminal app, especially when it comes to env variables, this is why I run next step via iTerm2.
- Now we are ready to proceed with the full installation, execute below command and follow instructions:
/bootstrap.shIn a full installation, the available ansible roles are executed in the following order:
- defaults
- homebrew_packages
- bitwarden
- chezmoi
- config_files
- gpg_import
- krew_plugins
You can find a README file inside each of the roles folder.
In case this is not a fresh setup and tools are present, wrapper can be used to keep your system up to date, either for example to install a new package or re apply dotfile sylminks.
./bootstrap.sh --tags "brew" # It will install all packages found in the roles/homebrew_packages/vars/main.yamlAnsible roles, can be executed in a standalone mode in case bootstrap wrapper isn't useful in your case.
Some examples are found below:
ansible-playbook main_playbook.yml --ask-vault-pass # to execute all tasks
ansible-playbook main_playbook.yml --ask-vault-pass --tags "cz" # to execute only specific roles which uses encrypted files
ansible-playbook main_playbook.yml --tags "brew", "krew" # to execute package and krew installationIf you want to create a new role:
ansible-galaxy init <role name>Include the role in your playbook:
- hosts: localhost
roles:
- {role: 'fancy_role', tags: 'fn'}In case you want to fork or download and adapt the code found in the repository, it is strongly recommended that you encrypt files like key.txt (used for exampl by Chezmoi Age Encryption) and any other file that holds sensitive info. I haven't done it here in order to show you what an age file would look like before encryption, in case you want to follow the same setup.
Check ansible-vault, transcrypt and Chezmoi encryption for more details.
In case you do have a separate repo for your dotfiles, gpg keys etc , then update chezmoi_init_url, gitlab_repo_url variable in the roles that use it (chezmoi, config_files, gpg_import). Otherwise, comment out the relevant roles in main main_playbook.yml.
This procedure is heavily depended to Bitwarden in order to retrieve tokens used during the playbook runtime. If you intend to use this only for package installation, then disable all roles except homebrew_packages.
The homebrew_packages role is designed to install only the packages listed under brew_cask_packages and brew_packages by default — these are packages I want available on every machine.
For fresh installations, I also want to include the packages listed under brew_cask_bootstrap_packages. However, I don’t want these bootstrap packages to be installed every time I run the role.
To handle this, I’ve added a flag in homebrew_packages/defaults/main.yml. You can either:
• Set the flag to true, or
• Use the corresponding Ansible tag to trigger the bootstrap package installation.
ansible-playbook main_playbook.yml --tags "brew" --extra-vars install_cask_bootsrap_packages=trueFor more customization details, check README files found in each roles folder (wip).
- Include usage examples and dependencies in each role's README files.
- bootstrap script may need some more sanity checks.
- merge similar tasks, like cloning and decrypting repos used during the fresh installation, in one role.
gpg_importrole is re-importing keys even if the keys are present.
Contributions and suggestions are welcome! If you spot something that could be improved (and I'm sure you'll find a lot :) ), please open an issue or submit a pull request.
I'm a DevOps Engineer specializing in hybrid infrastructure architecture and implementation. I design, deploy, and optimize systems across both on-premise environments and cloud platforms, focusing on automation, CI/CD pipelines, and infrastructure as code to create scalable, resilient solutions.
