diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f473fa..a0c0992 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ - do not use run_once instructions as it is wildly unreliable - typo in credentials template preventing from generating the initial credential file -## 0.4.0 (2024-07-10) +## v0.4.0 (2024-07-10) ### Feat @@ -57,14 +57,14 @@ - implement longer wait to stabilize consul cluster before bootstrapping to avoid timeout errors -## 0.3.0 (2024-05-13) +## v0.3.0 (2024-05-13) ### Feat - **generate_credentials**: generate new accesor ids and vault token credentials - **vault**: enable consul service registration automatically if consul is also enabled -## 0.2.0 (2024-05-05) +## v0.2.0 (2024-05-05) ### Feat @@ -75,7 +75,7 @@ - **globals**: restore default globals.yml file, move changes to test directory - **vault/consul**: ensure idempotence of extra_volumes list to avoid restarting on each run due to slightly different service files -## 0.1.0 (2024-05-03) +## v0.1.0 (2024-05-03) ### Feat diff --git a/README.md b/README.md index e9c79c7..c7d3f19 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,46 @@ -# Ansible Collection - ednz_cloud.hashistack +# πŸš€ hashistack-ansible Collection -THIS REPOSITORY IS A WORK IN PROGRESS, IT IS NOWHERE NEAR FIT FOR PRODUCTION. +![Ansible Badge](https://img.shields.io/badge/Ansible-E00?logo=ansible&logoColor=fff&style=for-the-badge) +![HashiCorp Badge](https://img.shields.io/badge/HashiCorp-000?logo=hashicorp&logoColor=fff&style=for-the-badge) +![Nomad Badge](https://img.shields.io/badge/Nomad-00CA8E?logo=nomad&logoColor=fff&style=for-the-badge) +![Vault Badge](https://img.shields.io/badge/Vault-FFEC6E?logo=vault&logoColor=000&style=for-the-badge) +![Consul Badge](https://img.shields.io/badge/Consul-F24C53?logo=consul&logoColor=fff&style=for-the-badge) + +Welcome to hashistack-ansible! This Ansible collection is your one-stop solution for deploying and managing HashiCorp product clusters with ease. Whether you're setting up Vault, Consul, or Nomad, this collection automates the entire process, allowing you to focus on building and scaling your infrastructure without the hassle. Let's dive into what this collection offers! 🌟 + +## 🎯 Features + +### πŸ”§ Deploy from Scratch + +Set up a fully integrated HashiStack environment with Vault, Consul, and Nomad from the ground up. Our playbooks ensure seamless integration between these services, enabling you to hit the ground running without manual setup. + +### 🎯 Targeted and Global Updates + +Update specific parts of your infrastructure using tags to target individual components or perform global updates to keep your entire stack in sync. This flexibility ensures minimal downtime and smooth rollouts. + + +### πŸ” Comprehensive Certificate Authority Management + +Easily manage your cluster's certificates with playbooks that handle the creation, renewal, and distribution of certificates across your infrastructure. This includes Root CAs, intermediates, and service-specific leaf certificates, ensuring secure communication throughout your environment. + +### πŸ”„ Rolling Updates for High Availability + +Perform control plane upgrades with rolling updates, ensuring that your services stay online and available during the upgrade process. This minimizes risk and maximizes uptime. + +## πŸ› οΈ How to Get Started + +1. Head to the [Quick-Start Guide](https://git.ednz.fr/ansible-collections/hashistack/wiki/02-quick-start) + + This should give you a good idea of how the collection works, and what it can do. + +2. From there, you can follow the rest of the [Documentation](https://git.ednz.fr/ansible-collections/hashistack/wiki/01-introduction) + + This will allow you to customize your deployment to your exact needs ! + +## πŸ§‘β€πŸ’» Contributions & Feedback + +We welcome contributions and feedback! If you encounter any issues or have suggestions for improvement, feel free to open an issue or submit a pull request. Let's make hashistack-ansible even better together! 🀝 + +## πŸ“„ License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. diff --git a/assets/boundary_500x500.png b/assets/boundary_500x500.png new file mode 100755 index 0000000..3d15612 Binary files /dev/null and b/assets/boundary_500x500.png differ diff --git a/assets/boundary_white_500x500.png b/assets/boundary_white_500x500.png new file mode 100755 index 0000000..5b65c04 Binary files /dev/null and b/assets/boundary_white_500x500.png differ diff --git a/assets/consul_500x500.png b/assets/consul_500x500.png new file mode 100755 index 0000000..d3a4037 Binary files /dev/null and b/assets/consul_500x500.png differ diff --git a/assets/consul_white_500x500.png b/assets/consul_white_500x500.png new file mode 100755 index 0000000..54db586 Binary files /dev/null and b/assets/consul_white_500x500.png differ diff --git a/assets/hashicorp_500x500.png b/assets/hashicorp_500x500.png new file mode 100755 index 0000000..86761ff Binary files /dev/null and b/assets/hashicorp_500x500.png differ diff --git a/assets/nomad_500x500.png b/assets/nomad_500x500.png new file mode 100755 index 0000000..4320ded Binary files /dev/null and b/assets/nomad_500x500.png differ diff --git a/assets/nomad_white_500x500.png b/assets/nomad_white_500x500.png new file mode 100755 index 0000000..a11a1aa Binary files /dev/null and b/assets/nomad_white_500x500.png differ diff --git a/assets/packer_500x500.png b/assets/packer_500x500.png new file mode 100755 index 0000000..8c849dd Binary files /dev/null and b/assets/packer_500x500.png differ diff --git a/assets/packer_white_500x500.png b/assets/packer_white_500x500.png new file mode 100755 index 0000000..a70bd06 Binary files /dev/null and b/assets/packer_white_500x500.png differ diff --git a/assets/terraform_500x500.png b/assets/terraform_500x500.png new file mode 100755 index 0000000..4b11821 Binary files /dev/null and b/assets/terraform_500x500.png differ diff --git a/assets/terraform_white_500x500.png b/assets/terraform_white_500x500.png new file mode 100755 index 0000000..adaa222 Binary files /dev/null and b/assets/terraform_white_500x500.png differ diff --git a/assets/vagrant_500x500.png b/assets/vagrant_500x500.png new file mode 100755 index 0000000..f0c33d4 Binary files /dev/null and b/assets/vagrant_500x500.png differ diff --git a/assets/vagrant_white_500x500.png b/assets/vagrant_white_500x500.png new file mode 100755 index 0000000..5bb94d2 Binary files /dev/null and b/assets/vagrant_white_500x500.png differ diff --git a/assets/vault_500x500.png b/assets/vault_500x500.png new file mode 100755 index 0000000..a0bed29 Binary files /dev/null and b/assets/vault_500x500.png differ diff --git a/assets/vault_white_500x500.png b/assets/vault_white_500x500.png new file mode 100755 index 0000000..233d25a Binary files /dev/null and b/assets/vault_white_500x500.png differ diff --git a/assets/waypoint_500x500.png b/assets/waypoint_500x500.png new file mode 100755 index 0000000..1501e82 Binary files /dev/null and b/assets/waypoint_500x500.png differ diff --git a/assets/waypoint_white_500x500.png b/assets/waypoint_white_500x500.png new file mode 100755 index 0000000..1c88a22 Binary files /dev/null and b/assets/waypoint_white_500x500.png differ diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..6034cfe --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +You can find the documentation for this project in the [Wiki](https://git.ednz.fr/ansible-collections/hashistack/wiki) diff --git a/docs/architecture_guide.md.md b/docs/architecture_guide.md.md deleted file mode 100644 index f8e9b29..0000000 --- a/docs/architecture_guide.md.md +++ /dev/null @@ -1,97 +0,0 @@ -# Architecture Guide - -Hashistack-Ansible allows you to deploy a number of architecture, wether you want to deploy a dev, testing, or production environment. These different architectures are described in this section. - -## Dev deployment - -If you only want to deploy a test environment, you can simply add a simgle host to each service that you want to deploy. - -```ini -[haproxy_servers] - -[vault_servers] -test01 - -[consul_servers] -test01 - -[nomad_servers] -test01 -``` - -In this example, you will end end with each service running on a single host, with no clustering, and no redundancy. This setup *IS NOT RECOMMENDED** for anything but testing purposes, as it provides zero resiliency, and will break if anything goes down. - -For this setup, the only requirement is for the target host to have a network interface that you can ssh into from the deployment host. - -The architecture would like something like this: - -```mermaid -graph LR; - client[Client] -->|http| server{ - Vault Server - Consul Server - Nomad Server - }; -``` - -## Testing/Preprod deployment - -For testing, of pre-production deployments, running all services on the same nodes might be a good way to cut cost and/or save resources. - -## Production deployment - -For production use, it is recommended to separate concerns as much as possible. This means that consul, vault and nomad, as well as the haproxy services, should be on different nodes altogether. The **client-facing** and **cluster-facing** interfaces should also be separated. - -Ideally, you would need: - - an odd number (3 to 5) of consul servers - - an odd number (3 to 5) of vault servers - - an odd number (3 to 5) of nomad servers - - multiple (2 to 3) haproxy servers - -The **nomad**, **vault** and **consul** servers should have **two network interfaces**, and one of them should be reachable from the haproxy nodes. - -The architecture for this infrastructure would look like: - -```mermaid -graph TD - client[Client] -->|https :443| keepalived - keepalived[VIP] --> haproxy1[HAProxy] & haproxy2[HAProxy] - subgraph frontends - direction LR - haproxy1[HAProxy] - haproxy2[HAProxy] - end - - haproxy1[HAProxy] & haproxy2[HAProxy] -->|http :8500| consul - - subgraph consul - direction LR - consul1[Consul 01] <--> consul2[Consul 02] & consul3[Consul 03] & consul4[Consul 04] & consul5[Consul 05] - consul2[Consul 02] <--> consul3[Consul 03] & consul4[Consul 04] & consul5[Consul 05] - consul3[Consul 03] <--> consul4[Consul 04] & consul5[Consul 05] - consul4[Consul 04] <--> consul5[Consul 05] - - end - - haproxy1[HAProxy] & haproxy2[HAProxy] -->|http :8200| vault - - subgraph vault - direction LR - vault1[Vault 01] <--> vault2[Vault 02] - vault2[Vault 02] <--> vault3[Vault 03] - vault3[Vault 03] <--> vault1[Vault 01] - end - - vault -->|Service registration| consul - haproxy1[HAProxy] & haproxy2[HAProxy] -->|http :4646| nomad - - subgraph nomad - direction LR - nomad1[Nomad 01] <--> nomad2[Nomad 02] - nomad2[Nomad 02] <--> nomad3[Nomad 03] - nomad3[Nomad 03] <--> nomad1[Nomad 01] - end - - nomad -->|Service registration| consul -``` -> **Note**: you can substract the haproxy part if using an external load-balancing solution, like AWS ALB,or any other LB technology, for connecting to your platform. diff --git a/docs/consul_clusters.md b/docs/consul_clusters.md deleted file mode 100644 index 462dd91..0000000 --- a/docs/consul_clusters.md +++ /dev/null @@ -1,3 +0,0 @@ -# Deploying a Consul cluster - -This documentation explains each steps necessary to successfully deploy a Consul cluster using the ednz_cloud.hashistack ansible collection. diff --git a/docs/extra_configuration.md b/docs/extra_configuration.md deleted file mode 100644 index cff5628..0000000 --- a/docs/extra_configuration.md +++ /dev/null @@ -1 +0,0 @@ -# Adding extra configuration options diff --git a/docs/general.md b/docs/general.md deleted file mode 100644 index 11459ae..0000000 --- a/docs/general.md +++ /dev/null @@ -1,103 +0,0 @@ -# General documentation - -## Configuration directory - -### Main configuration directory - -Hashistack Ansible uses a configuration directory to store all the configuration files and other artifacts. - -This directory is defined with the variable `hashistack_configuration_directory`. By default, it will look at `{{ lookup('env', 'PWD') }}/etc/hashistack`, which equals `$(pwd)/etc/hashistack`. - -Under this directory, you are expected to place the `globals.yml` file, with your configuration. - -### Sub configuration directories - -#### Group configuration directories - -Additionally, subdirectories can be used to tailor the configuration further. - -Each group within the `inventory` will look at a directory named after itself: - -- nomad_servers group will look for `{{ hashistack_configuration_directory }}/nomad_servers` -- vault_servers group will look for `{{ hashistack_configuration_directory }}/vault_servers` -- consul_servers group will look for `{{ hashistack_configuration_directory }}/consul_servers` - -Within each of these directories, you can place an additional `globals.yml file`, that will superseed the file at the root of the configuration directory. - -- **Example**: - - If `etc/hashistack/globals.yml` looks like: - - ```yaml - --- - enable_vault: "no" - enable_consul: "no" - enable_nomad: "no" - ``` - - And `etc/hashistack/nomad_servers/globals.yml` looks like: - - ```yaml - --- - enable_nomad: "yes" - ``` - - Servers in the `nomad_servers` group will end up with the following configuration: - - ```yaml - --- - enable_vault: "no" - enable_consul: "no" - enable_nomad: "yes" - ``` - -This approach lets you customize your deployment for your exact needs. - -#### Host configuration directories - -Additionally, within each `group configuration directory`, you can add `host configuration directory`, that will be named after the hosts defined in your `inventory`. These host directories can also be populated with a `globals.yml` file, that will superseed the `group` and `deployment` configuration files. - -- **Example** - - If `etc/hashistack/globals.yml` looks like: - - ```yaml - --- - enable_vault: "no" - enable_consul: "no" - enable_nomad: "no" - api_interface: "eth0" - ``` - - And `etc/hashistack/nomad_servers/globals.yml` looks like: - - ```yaml - --- - enable_nomad: "yes" - api_interface: "eth1" - ``` - - And `etc/hashistack/nomad_servers/nomad-master-01/globals.yml` looks like: - - ```yaml - api_interface: "eth0.vlan40" - ``` - - Servers in the `nomad_servers` group will end up with the following configuration: - - ```yaml - --- - enable_vault: "no" - enable_consul: "no" - enable_nomad: "yes" - api_interface: "eth1" - ``` - Except for host `nomad-master-01`, who will have the following: - - ```yaml - --- - enable_vault: "no" - enable_consul: "no" - enable_nomad: "yes" - api_interface: "eth0.vlan40" - ``` diff --git a/docs/haproxy_servers.md b/docs/haproxy_servers.md deleted file mode 100644 index 3bbda8f..0000000 --- a/docs/haproxy_servers.md +++ /dev/null @@ -1,104 +0,0 @@ -# Deploying HAProxy frontends - -This documentation explains each steps necessary to successfully deploy HAProxy frontends for your deployment, using the ednz_cloud.hashistack ansible collection. - -## Prerequisites - -You should, before attempting any deployment, have read through the [Quick Start Guide](./quick_start.md). These steps are necessary in order to ensure smooth operations going forward. - -## Variables - -### Basics - -First, in order to deploy the HAproxy frontends, you need to enable the deployment. - -```yaml -enable_haproxy: "yes" -``` - -You can also configure the version of haproxy you would like to use. This has very little impact, and should most likely be left untouched to whatever the collection version is defaulting to (which is the version that it is tested against). - -```yaml -haproxy_version: "2.8" -``` -This version can either be `latest`, or any `X`, `X.Y`, `X.Y.Z` tag of the [haproxytech/haproxy-debian](https://hub.docker.com/r/haproxytech/haproxy-debian) docker image. - -For production deployment, it is recommended to use the `X.Y.Z` syntax. - -The `deployment_method` variable will define how to install vault on the nodes. - -By default, it runs haproxy inside a docker container, but this can be changed to `host` to install haproxy from the package manager. - -Note that not all versions of haproxy are available as a package on all supported distributions. Please refer to the documentation of [ednz_cloud.deploy_haproxy](https://github.com/ednz-cloud/deploy_haproxy) for details about supported versions when installing from the package manager. - -```yaml -deployment_method: "docker" -``` - -### General settings - -There aren't many settings that you can configure to deploy the HAProxy frontends. First you'll need to configure a Virtual IP, and pass it in the `globals.yml` configuration file. - -```yaml -hashistack_external_vip_interface: "eth0" -hashistack_external_vip_addr: "192.168.121.100" -``` - -This is used to configure keepalived to automatically configure this VIP on one of the frontend, and handle failover. - -You also need to configure the names that will resolve to your different applications (consul, nomad, vault). These names should resolve to your Virtual IP, and will be used to handle host-based routing on haproxy. - -```yaml -consul_fqdn: consul.ednz.lab -vault_fqdn: vault.ednz.lab -nomad_fqdn: nomad.ednz.lab -``` - -With this configuration, querying `http://consul.ednz.lab` will give you the consul UI and API, through haproxy. - -> Note: subpaths are not yet supported, so you cannot set the fqdn to `generic.domain.tld/consul`. This feature will be added in a future release. - -### Enabling external TLS - -To enable external TLS for your APIs and UIs, you will need to set the following variable. - -```yaml -enable_tls_external: true -``` - -This will enable the https listener for haproxy and configure the http listener to be a https redirect only. - -## Managing external TLS certificates - -### Generating certificates with hashistack-ansible - -If you don't care about having trusted certificates (e.g. for developement or testing purposes), you can generate some self-signed certificates for your applications using the `generate_certs.yml` playbook. - -```bash -ansible-playbook -i multinode.ini ednz_cloud.hashistack.generate_certs.yml -``` - -This will generate self-signed certificates for each applications that has been enabled in your `globals.yml`, and for then respective fqdn (also configured in `globals.yml`). - -These certificates are going to be placed in `etc/hashistack/certificates/external/`, and will be named after each fqdn. These files should be encrypted using something like ansible-vault, as they are sensitive. - -### Managing your own TLS certificates - -Similarly, you can manage your own TLS certificates, signed by your own CA. Your certificates should be placed in the `etc/hashistack/certificates/external/` directory, similar to the self-signed ones, and be named like: - -`.pem` and `.pem.key`, for each application. - -At the moment, setting all certificates in a single file is not supported, but will be added in a later release. - -These certificates will be copied over to the `haproxy_servers` hosts, in `/var/lib/haproxy/certs/`. - - -### Managing certificates externally - -In case you already have systems in place to deploy and renew your certificates, you can simply enable the options in `globals.yml` to not manage certificates directly in hashistack-ansible. - -```yaml -external_tls_externally_managed_certs: true -``` - -Enabling this option will prevents the playbooks from trying to copy certificates over, but the HAProxy nodes will still expect them to be present. It is up to you to copy them over. diff --git a/docs/nomad_clusters.md b/docs/nomad_clusters.md deleted file mode 100644 index e1d7140..0000000 --- a/docs/nomad_clusters.md +++ /dev/null @@ -1,82 +0,0 @@ -# Deploying a Nomad cluster - -This documentation explains each steps necessary to successfully deploy a Nomad cluster using the ednz_cloud.hashistack ansible collection. - -## Prerequisites - -You should, before attempting any deployment, have read through the [Quick Start Guide](./quick_start.md). These steps are necessary in order to ensure smooth operations going forward. - -## Variables - -### Basics - -First, in order to deploy a nomad cluster, you need to enable it. - -```yaml -enable_nomad: "yes" -``` - -Selecting the nomad version to install is done with the `nomad_version` variable. - -```yaml -nomad_version: latest -``` - -The vault version can either be `latest` or `X.Y.Z`. - -For production deployment, it is recommended to use the `X.Y.Z` syntax. - -### General settings - -First, you can change some general settings for nomad, like the dc and region options. - -```yaml -nomad_datacenter: dc1 -nomad_region: global -``` - -### ACLs settings - -By default, ACLs are enabled on nomad, and automatically bootstrapped. -You can change this by editing the `nomad_acl_configuration` variable: - -```yaml -nomad_acl_configuration: - enabled: true - token_ttl: 30s - policy_ttl: 60s - role_ttl: 60s -``` - -### Consul integration settings - -By default, if consul if also enabled, nomad will use it to register itself as a consul service and also use consul to automatically join the cluster. - -```yaml -nomad_enable_consul_integration: "{{ enable_consul | bool }}" -nomad_consul_integration_configuration: - address: "127.0.0.1:{{ hashicorp_consul_configuration.ports.https if consul_enable_tls else hashicorp_consul_configuration.ports.http }}" - auto_advertise: true - ssl: "{{ consul_enable_tls | bool }}" - token: "{{ _credentials.consul.tokens.nomad.server.secret_id if nomad_enable_server else _credentials.consul.tokens.nomad.client.secret_id}}" - tags: [] -``` - -Optionally, you can add tags to you nomad services, or disable the consul integration if you don't plan on using it. - -### Vault integration settings - -Vault integration for nomad is by default disabled, as it requires some vault configuration that is out of the scope of this collection. - -You can, once you have deployed and configured vault (or if you are using an external vault not managed by the collection), enable the integration - -```yaml -nomad_enable_vault_integration: false -nomad_vault_integration_configuration: {} -``` - -For configuration options, please refer to the [Official Documentation](https://developer.hashicorp.com/nomad/docs/configuration/vault) - -### Drivers settings - -### Internal TLS diff --git a/docs/quick_start.md b/docs/quick_start.md deleted file mode 100644 index c06db76..0000000 --- a/docs/quick_start.md +++ /dev/null @@ -1,154 +0,0 @@ -# Quick Start Guide - -This documentation will show you the preparation steps necessary to ensure that you environment is ready to deploy cluster(s). - -## Prerequisites - -### Recommended readings - -It’s beneficial to learn basics of both [Ansible](https://docs.ansible.com/) and [Docker](https://docs.docker.com/)(for docker deployments) before running Hashistack Ansible. - -### Operating - -The only supported operating systems currently are: -- Debian - - 11, Bullseye - - 12, Bookworm -- Ubuntu - - 20.04, Focal - - 22.04, Jammy - -Other Debian-based distributions might work, but **are not tested**, and may break at any given update. - -### Target Hosts - -Target hosts are the hosts you are planning on deploying cluster(s) to. - -These hosts must satisfy the following minimum requirements: -- Be reachable via ssh by the deployment node (the machine running the ansible playbooks), with a user that has the ability to escalate privileges. -- Be able to comunicate with each other, according to your cluster topology (vault hosts must all be able to reach each other, etc...) -- Be synced to a common time -- Have less than 10ms of latency to reach each other (raft consensus algorithm requirement) -- Be using systemd as their init system. - -Ideally, hosts are recommended to satisfy the following recommendations: -- Have 2 network interfaces: - - One that is public facing for client-to-server traffic - - One that is not public facing for server-to-server and deployment-to-server communications -- Have a minimum of 8GB of memory (less will work, but the larger the scale, the higher the RAM requirements will be) -- Have a minimum of 40GB of free disk space - -## Prepare the deployment host - -1. Install the virtual environment dependencies. - -```bash -sudo apt update -sudo apt install git python3-dev libffi-dev gcc libssl-dev python3-venv -``` - -2. Create a python virtual environment and activate it. - -```bash -python3 -m venv /path/to/venv -source /path/to/venv/bin/activate -``` - -3. Ensure the latest version of pip is installed - -```bash -pip install -U pip -``` - -4. Install [Ansible](http://www.ansible.com/). Hashistack-Ansible requires at least Ansible **7**(or ansible-core **2.15**) - -```bash -pip install 'ansible-core>=2.15' -``` - -5. Create the directory structure. This is not required but **heavily** recommended. - -```bash -mkdir -p etc/hashistack collections inventory roles -touch ansible.cfg -``` - -Your directory structure should look like this - -```bash -. -β”œβ”€β”€ ansible.cfg -β”œβ”€β”€ collections -β”œβ”€β”€ etc -β”‚Β Β  └── hashistack -β”œβ”€β”€ inventory -└── roles -``` - -6. Edit the `ansible.cfg` file with the minimum requirements. - -```bash -[defaults] -roles_path = ./roles/ -collections_path = ./collections/ -inventory = ./inventory/ -``` - -7. Install the `ednz_cloud.hashistack` ansible collection - -```bash -ansible-galaxy collection install ednz_cloud.hashistack:== -``` - -You should now have a directory under `./collections/ansible_collections/ednz_cloud/hashistack` - -8. Install the other dependencies required by `ednz_cloud.hashistack` - -```bash -ansible-galaxy install -r ./collections/ansible_collections/ednz_cloud/hashistack/roles/requirements.yml -``` - -This will install roles that are not packaged with the collection, but are still required in order to run the playbooks. - -You should now have some roles inside `./roles/`. - -9. Copy `inventory` file and `globals.yml `file locally - -```bash -cp collections/ansible_collections/ednz_cloud/hashistack/playbooks/inventory/multinode.ini inventory/ -``` - -```bash -cp collections/ansible_collections/ednz_cloud/hashistack/playbooks/group_vars/all/globals.yml etc/hashistack/globals.yml -``` - -## Generate Credentials - -Before deploying your infrastructure with Hashistack-Ansible, you need to generate credentials that will be used to bootstrap the various clusters. - -This can be done by running the `generate_credentials.yml` playbook. - -```bash -ansible-playbook -i inventory/inventory.ini ednz_cloud.hashistack.generate_credentials.yml -``` - -This will create and populate `etc/hashistack/secrets/credentials.yml` - -> [!WARNING] -> This file is VERY SENSITIVE, as it holds the root tokens and other credentials for consul and nomad clusters. - -This does not generate vault credentials, as it is not possible to generate those in advance. These credentials will be generated, if you enable the vault deployment, during the bootstrap process of the vault cluster, and stored in `etc/hashistack/secrets/vault.yml` - -> [!WARNING] -> It is HIGHLY recommended to encrypt these two files before enventually commiting them to source control. You can do so using tools like [ansible-vault](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html) or [sops](https://github.com/getsops/sops). - -## Running preflight checks and bootstrap playbooks - -Before running the main deployment playbook, you might want to run the `bootstrap` and `preflight` playbooks, which do a number of checks to ensure all hosts are setup correctly for deployment. - -```bash -ansible-playbook -i inventory/inventory.ini ednz_cloud.hashistack.bootstrap.yml -ansible-playbook -i inventory/inventory.ini ednz_cloud.hashistack.preflight.yml -``` - -These playbooks will run a number of checks, and installations, in order to ensure the target hosts, as well as your deployment environment are correctly setup in order to install all the components. diff --git a/docs/tls_guide.md b/docs/tls_guide.md deleted file mode 100644 index 2eb4699..0000000 --- a/docs/tls_guide.md +++ /dev/null @@ -1,6 +0,0 @@ -# TLS Guide - - -create certificate/ca directory - -`ansible-playbook -i inventory/multinode.ini ednz_cloud.hashistack.generate_certs.yml` diff --git a/docs/vault_clusters.md b/docs/vault_clusters.md deleted file mode 100644 index 96ed1cc..0000000 --- a/docs/vault_clusters.md +++ /dev/null @@ -1,107 +0,0 @@ -# Deploying a Vault cluster - -This documentation explains each steps necessary to successfully deploy a Vault cluster using the ednz_cloud.hashistack ansible collection. - -## Prerequisites - -You should, before attempting any deployment, have read through the [Quick Start Guide](./quick_start.md). These steps are necessary in order to ensure smooth operations going forward. - -## Variables - -### Basics - -First, in order to deploy a Vault cluster, you need to enable it. - -```yaml -enable_vault: "yes" -``` - -Selecting the vault version to install is done with the `vault_version` variable. - -```yaml -vault_version: latest -``` - -The vault version can either be `latest` or `X.Y.Z`. - -For production deployment, it is recommended to use the `X.Y.Z` syntax. - -### General settings - -First, you can change some general settings for vault. - -```yaml -vault_cluster_name: vault -vault_enable_ui: true -vault_seal_configuration: - key_shares: 3 - key_threshold: 2 -``` - -### Storage settings - -The storage configuration for vault can be edited as well. By default, vault will be configured to setup `raft` storage between all declared vault servers (in the `vault_servers` group). - -```yaml -vault_storage_configuration: - raft: - path: "{{ hashicorp_vault_data_dir }}/data" - node_id: "{{ ansible_hostname }}" - retry_join: | - [ - {% for host in groups['vault_servers'] %} - { - 'leader_api_addr': 'http://{{ hostvars[host].api_interface_address }}:8200' - }{% if not loop.last %},{% endif %} - {% endfor %} - ] -``` - -While this is the [recommended](https://developer.hashicorp.com/vault/docs/configuration/storage#integrated-storage-vs-external-storage) way to configure storage for vault, you can edit this variable to enable any storage you want. Refer to the [vault documentation](https://developer.hashicorp.com/vault/docs/configuration/storage) for compatibility and syntax details about this variable. - -Example: - -```yaml -# MySQL storage configuration -vault_storage_configuration: - mysql: - address: "10.1.10.10:3006" - username: "vault" - password: "vault" - database: "vault" -``` - -### Listener settings - -#### TCP listeners - -By default, TLS is **disabled** for vault. This goes against the Hashicorp recommendations on the matter, but there is no simple way to force the use of TLS (yet), without adding a lot of complexity to the deployment. - -The listener configuration settings can be modified in `vault_listener_configuration` variable. - -```yaml -vault_listener_configuration: - tcp: - address: "0.0.0.0:8200" - tls_disable: true -``` -By default, vault will listen on all interfaces, on port 8200. you can change it by modifying the `tcp.address` property, and adding you own listener preferences. - -#### Enabling TLS for Vault - -In order to enable TLS for Vault, you simply need to set the `vault_enable_tls` variable to `true`. - -At the moment, hashistack-Ansible does nothing to help you generate the certificates and renew them. All it does is look inside the `etc/hashistack/vault_servers/tls` directory on the deployment node, and copy the files to the destination hosts in `/etc/vault.d/config/tls`. The listener expect **2 files** by default, a `cert.pem`, and a `key.pem` file. - -Please refer to the [vault documentation](https://developer.hashicorp.com/vault/docs/configuration/listener/tcp) for details bout enabling TLS on vault listeners. - -In case you want to add more configuration to the vault listeners, you can add it to the `vault_extra_listener_configuration` variable, which by default is empty. This variable will be merge with the rest ofthe listener configuration variables, and takes precedence over all the others. - -> **Waring** -> At the moment, hashistack-ansible does not support setting up multiple TCP listeners. Only one can be set. - -### Plugins for Vault - -To enable plugin support for Vault, you can set the `vault_enable_plugins` variable to true. This variable will add the necessary configuration options in the vault.json file to enable support. Once enabled, you can simply place your compiled plugin files into the `etc/hashistack/vault_servers/plugin` directory. They will be copied over to the `/etc/vault.d/config/plugin` directory on the target nodes. - -Refer to the [vault documentation](https://developer.hashicorp.com/vault/docs/plugins/plugin-management) for details about enabling and using plugins. diff --git a/galaxy.yml b/galaxy.yml index d979ddd..f89e03c 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -21,7 +21,8 @@ issues: http://example.com/issue/tracker # artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This # uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', # and '.git' are always filtered. Mutually exclusive with 'manifest' -build_ignore: [] +build_ignore: + - assets/* # A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a # list of MANIFEST.in style # L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key diff --git a/molecule/no_tls_multi_node/etc/hashistack/consul_servers/.gitkeep b/molecule/no_tls_multi_node/etc/hashistack/consul_servers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/molecule/no_tls_multi_node/etc/hashistack/globals.yml b/molecule/no_tls_multi_node/etc/hashistack/globals.yml index 66f4777..4a02ac8 100644 --- a/molecule/no_tls_multi_node/etc/hashistack/globals.yml +++ b/molecule/no_tls_multi_node/etc/hashistack/globals.yml @@ -1,12 +1,6 @@ --- # Molecule specific variables -hashistack_ca_action: "root_ca,int_ca,leaf_cert,renew_root," -hashistack_ca_directory: "{{ hashistack_sub_configuration_directories['certificates'] }}" -hashistack_ca_directory_owner: "{{ lookup('env', 'USER') }}" -hashistack_ca_domain: ednz.lab -hashistack_ca_intermediate_name_constraints_critical: false - ########################## # General options ######## ########################## @@ -37,14 +31,14 @@ api_interface: "eth1" # external tls options # ######################## -enable_tls_external: true +# enable_tls_external: false # external_tls_externally_managed_certs: false ######################## # internal tls options # ######################## -enable_tls_internal: true +# enable_tls_internal: false # internal_tls_externally_managed_certs: false ##################################################### diff --git a/molecule/no_tls_multi_node/etc/hashistack/haproxy_servers/globals.yml b/molecule/no_tls_multi_node/etc/hashistack/haproxy_servers/globals.yml deleted file mode 100644 index 5d6ecdc..0000000 --- a/molecule/no_tls_multi_node/etc/hashistack/haproxy_servers/globals.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -nomad_client_configuration: - enabled: "{{ nomad_enable_client }}" - state_dir: "{{ nomad_data_dir }}/client" - cni_path: "{{ cni_plugins_install_path | default('/opt/cni/bin') }}" - bridge_network_name: nomad - bridge_network_subnet: "172.26.64.0/20" - node_pool: ingress diff --git a/molecule/no_tls_multi_node/etc/hashistack/vault_servers/.gitkeep b/molecule/no_tls_multi_node/etc/hashistack/vault_servers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/molecule/no_tls_multi_node/prepare.yml b/molecule/no_tls_multi_node/prepare.yml index 9973f22..98b7baf 100644 --- a/molecule/no_tls_multi_node/prepare.yml +++ b/molecule/no_tls_multi_node/prepare.yml @@ -1,6 +1,6 @@ --- - name: Include certificate generation playbook - ansible.builtin.import_playbook: ednz_cloud.hashistack.generate_certs.yml + ansible.builtin.import_playbook: ednz_cloud.hashistack.certificates.yml - name: Include bootstrap playbook ansible.builtin.import_playbook: ednz_cloud.hashistack.bootstrap.yml diff --git a/molecule/tls_multi_node/converge.yml b/molecule/tls_multi_node/converge.yml new file mode 100644 index 0000000..daad78c --- /dev/null +++ b/molecule/tls_multi_node/converge.yml @@ -0,0 +1,3 @@ +--- +- name: Include a playbook from a collection + ansible.builtin.import_playbook: ednz_cloud.hashistack.deploy.yml diff --git a/molecule/tls_multi_node/etc/hashistack/globals.yml b/molecule/tls_multi_node/etc/hashistack/globals.yml new file mode 100644 index 0000000..b0bca38 --- /dev/null +++ b/molecule/tls_multi_node/etc/hashistack/globals.yml @@ -0,0 +1,299 @@ +--- +# Molecule specific variables + +hashistack_ca_action: "root_ca,int_ca,leaf_cert,renew_root" +hashistack_ca_directory: "{{ hashistack_sub_configuration_directories['certificates'] }}" +hashistack_ca_directory_owner: "{{ lookup('env', 'USER') }}" +hashistack_ca_domain: ednz.lab +hashistack_ca_intermediate_name_constraints_critical: false + +########################## +# General options ######## +########################## + +# enable_haproxy: "yes" +# enable_vault: "yes" +# enable_consul: "yes" +# enable_nomad: "yes" + +# haproxy_version: "2.8" +nomad_version: "1.8.3" +# consul_version: "1.18.1" +vault_version: "1.17.2" + +# consul_fqdn: consul.ednz.lab +# vault_fqdn: vault.ednz.lab +# nomad_fqdn: nomad.ednz.lab + +# hashistack_external_vip_interface: "eth0" +# hashistack_external_vip_addr: "192.168.121.100" +# hashistack_internal_vip_interface: "{{ hashistack_external_vip_interface }}" +# hashistack_internal_vip_addr: "{{ hashistack_external_vip_addr }}" + +api_interface: "eth1" +# api_interface_address: "{{ ansible_facts[api_interface]['ipv4']['address'] }}" + +######################## +# external tls options # +######################## + +enable_tls_external: true +# external_tls_externally_managed_certs: false + +######################## +# internal tls options # +######################## + +enable_tls_internal: true +# internal_tls_externally_managed_certs: false + +##################################################### +# # +# Consul # +# # +##################################################### + +# consul_domain: consul +# consul_datacenter: dc1 +# consul_primary_datacenter: dc1 +# consul_leave_on_terminate: true +# consul_rejoin_after_leave: true +# consul_enable_script_checks: true +# consul_gossip_encryption_key: "{{ 'mysupersecretgossipencryptionkey'|b64encode }}" + +################################ +# consul address configuration # +################################ + +# consul_address_configuration: +# # The address to which Consul will bind client interfaces, +# # including the HTTP and DNS servers. +# client_addr: "0.0.0.0" +# # The address that should be bound to for internal cluster communications. +# bind_addr: "{{ api_interface_address }}" +# # The advertise address is used to change the address that we advertise to other nodes in the cluster. +# advertise_addr: "{{ api_interface_address }}" + +############################ +# consul ACL configuration # +############################ + +# consul_acl_configuration: +# enabled: true +# default_policy: "deny" # can be allow or deny +# enable_token_persistence: true + +############################ +# consul DNS configuration # +############################ + +# consul_dns_configuration: +# allow_stale: true +# enable_truncate: true +# only_passing: true + +########################### +# consul ui configuration # +########################### + +# consul_ui_configuration: +# enabled: "{{ 'consul_servers' in group_names }}" + +##################################### +# consul service mesh configuration # +##################################### + +# consul_mesh_configuration: +# enabled: true + +############################ +# consul tls configuration # +############################ + +# consul_enable_tls: "{{ enable_tls_internal }}" +# consul_tls_configuration: +# defaults: +# ca_file: "/etc/ssl/certs/ca-certificates.crt" +# cert_file: "{{ consul_certificates_directory }}/cert.pem" +# key_file: "{{ consul_certificates_directory }}/key.pem" +# verify_incoming: false +# verify_outgoing: true +# internal_rpc: +# verify_server_hostname: true + +############################ +# consul container volumes # +############################ + +# extra_consul_container_volumes: [] + +############################## +# consul extra configuration # +############################## + +# consul_extra_configuration: {} +# consul_extra_files_list: [] + +##################################################### +# # +# Vault # +# # +##################################################### + +# vault_cluster_name: vault +# vault_enable_ui: true +# vault_seal_configuration: +# key_shares: 3 +# key_threshold: 2 + +################# +# vault storage # +################# + +# vault_storage_configuration: +# raft: +# path: "{{ hashicorp_vault_data_dir }}/data" +# node_id: "{{ ansible_hostname }}" +# retry_join: | +# [ +# {% for host in groups['vault_servers'] %} +# { +# 'leader_api_addr': '{{ "https" if vault_enable_tls else "http"}}://{{ hostvars[host].api_interface_address }}:8200' +# }{% if not loop.last %},{% endif %} +# {% endfor %} +# ] + +################## +# vault listener # +################## + +# vault_enable_tls: "{{ enable_tls_internal }}" +# vault_tls_verify: false +# vault_listener_configuration: +# tcp: +# address: "0.0.0.0:8200" +# tls_disable: true + +# vault_tls_listener_configuration: +# tcp: +# tls_disable: false +# tls_cert_file: "{{ vault_certificates_directory }}/cert.pem" +# tls_key_file: "{{ vault_certificates_directory }}/key.pem" +# tls_disable_client_certs: true + +# vault_extra_listener_configuration: {} + +######################## +# service registration # +######################## + +# vault_enable_service_registration: false +# vault_service_registration_configuration: +# consul: +# address: "127.0.0.1:8500" +# scheme: "http" +# token: "" + +################# +# vault plugins # +################# + +# vault_enable_plugins: false + +########### +# logging # +########### + +# vault_enable_log_to_file: false +# vault_logging_configuration: +# log_level: info +# log_format: standard +# log_rotate_duration: 24h +# log_rotate_max_files: 30 + +########################### +# vault container volumes # +########################### + +# extra_vault_container_volumes: [] + +############################# +# vault extra configuration # +############################# + +# vault_extra_configuration: {} +# vault_extra_files_list: [] + +##################################################### +# # +# Nomad # +# # +##################################################### + +# nomad_datacenter: dc1 +# nomad_region: global + +########################### +# nomad ACL configuration # +########################### + +# nomad_acl_configuration: +# enabled: true +# token_ttl: 30s +# policy_ttl: 60s +# role_ttl: 60s + +############################ +# nomad consul integration # +############################ + +# nomad_enable_consul_integration: "{{ enable_consul | bool }}" +# nomad_consul_integration_configuration: +# address: "127.0.0.1:{{ hashicorp_consul_configuration.ports.https if consul_enable_tls else hashicorp_consul_configuration.ports.http }}" +# auto_advertise: true +# ssl: "{{ consul_enable_tls | bool }}" +# token: "{{ _credentials.consul.tokens.nomad.server.secret_id if nomad_enable_server else _credentials.consul.tokens.nomad.client.secret_id}}" +# tags: [] + +############################ +# nomad vault integration # +############################ + +# nomad_enable_vault_integration: false +# nomad_vault_integration_configuration: {} + +############################### +# nomad drivers configuration # +############################### + +# nomad_driver_enable_docker: yes +# nomad_driver_enable_podman: no +# nomad_driver_enable_raw_exec: no +# nomad_driver_enable_java: no +# nomad_driver_enable_qemu: no + +# nomad_driver_extra_configuration: {} + +###################### +# nomad internal tls # +###################### + +# nomad_enable_tls: "{{ enable_tls_internal }}" +# nomad_tls_configuration: +# http: true +# rpc: true +# ca_file: "/etc/ssl/certs/ca-certificates.crt" +# cert_file: "{{ nomad_certificates_directory }}/cert.pem" +# key_file: "{{ nomad_certificates_directory }}/key.pem" +# verify_server_hostname: true +# nomad_certificates_directory: "{{ hashicorp_nomad_config_dir }}/tls" +# nomad_certificates_extra_files_dir: +# - src: "{{ hashistack_sub_configuration_directories['certificates'] }}/nomad/{{ inventory_hostname }}" +# dest: "{{ nomad_certificates_directory }}" + +############################# +# nomad extra configuration # +############################# + +# nomad_extra_configuration: {} +# nomad_extra_files_list: [] diff --git a/molecule/tls_multi_node/molecule.yml b/molecule/tls_multi_node/molecule.yml new file mode 100644 index 0000000..39209e9 --- /dev/null +++ b/molecule/tls_multi_node/molecule.yml @@ -0,0 +1,116 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ./requirements.yml +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: proxy01.ednz.lab + box: generic/${MOLECULE_TEST_OS} + cpus: 2 + memory: 2048 + interfaces: + - network_name: private_network + ip: 192.168.100.91 + auto_config: true + type: static + groups: + - common + - haproxy_servers + - nomad_clients + - consul_agents + - name: proxy02.ednz.lab + box: generic/${MOLECULE_TEST_OS} + cpus: 2 + memory: 2048 + interfaces: + - network_name: private_network + ip: 192.168.100.92 + auto_config: true + type: static + groups: + - common + - haproxy_servers + - nomad_clients + - consul_agents + - name: hashistack01.ednz.lab + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 2048 + interfaces: + - network_name: private_network + ip: 192.168.100.101 + auto_config: true + type: static + groups: + - common + - vault_servers + - consul_servers + - nomad_servers + - nomad_clients + - name: hashistack02.ednz.lab + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 2048 + interfaces: + - network_name: private_network + ip: 192.168.100.102 + auto_config: true + type: static + groups: + - common + - vault_servers + - consul_servers + - nomad_servers + - nomad_clients + - name: hashistack03.ednz.lab + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 2048 + interfaces: + - network_name: private_network + ip: 192.168.100.103 + auto_config: true + type: static + groups: + - common + - vault_servers + - consul_servers + - nomad_servers + - nomad_clients + - name: hashistack04.ednz.lab + box: generic/${MOLECULE_TEST_OS} + cpus: 4 + memory: 2048 + interfaces: + - network_name: private_network + ip: 192.168.100.104 + auto_config: true + type: static + groups: + - common + - nomad_clients + - consul_agents +provisioner: + name: ansible + config_options: + defaults: + remote_tmp: /tmp/.ansible +verifier: + name: ansible +scenario: + name: tls_multi_node + test_sequence: + - dependency + - cleanup + - destroy + - create + - prepare + - converge + - idempotence + - verify + - cleanup + - destroy diff --git a/molecule/tls_multi_node/prepare.yml b/molecule/tls_multi_node/prepare.yml new file mode 100644 index 0000000..98b7baf --- /dev/null +++ b/molecule/tls_multi_node/prepare.yml @@ -0,0 +1,9 @@ +--- +- name: Include certificate generation playbook + ansible.builtin.import_playbook: ednz_cloud.hashistack.certificates.yml + +- name: Include bootstrap playbook + ansible.builtin.import_playbook: ednz_cloud.hashistack.bootstrap.yml + +- name: Include preflight playbook + ansible.builtin.import_playbook: ednz_cloud.hashistack.preflight.yml diff --git a/molecule/tls_multi_node/requirements.yml b/molecule/tls_multi_node/requirements.yml new file mode 100644 index 0000000..3dd371e --- /dev/null +++ b/molecule/tls_multi_node/requirements.yml @@ -0,0 +1,10 @@ +--- +# requirements file for molecule +roles: + - name: ednz_cloud.manage_repositories + - name: ednz_cloud.manage_apt_packages + - name: ednz_cloud.manage_pip_packages + - name: ednz_cloud.install_docker + +collections: + - name: ednz_cloud.hashistack diff --git a/molecule/tls_multi_node/verify.yml b/molecule/tls_multi_node/verify.yml new file mode 100644 index 0000000..5f1bb76 --- /dev/null +++ b/molecule/tls_multi_node/verify.yml @@ -0,0 +1,6 @@ +--- +- name: Verify + hosts: all + gather_facts: true + become: true + tasks: [] diff --git a/playbooks/generate_certs.yml b/playbooks/certificates.yml similarity index 100% rename from playbooks/generate_certs.yml rename to playbooks/certificates.yml diff --git a/playbooks/generate_credentials.yml b/playbooks/credentials.yml similarity index 100% rename from playbooks/generate_credentials.yml rename to playbooks/credentials.yml diff --git a/playbooks/deploy.yml b/playbooks/deploy.yml index 4e2f613..e183281 100644 --- a/playbooks/deploy.yml +++ b/playbooks/deploy.yml @@ -10,6 +10,9 @@ - name: "Import variables" ansible.builtin.include_role: name: ednz_cloud.hashistack.hashistack + apply: + tags: + - always tags: - always @@ -17,39 +20,39 @@ - name: "Deploy Consul" tags: - consul + - consul_servers + - consul_agents when: - enable_consul | bool ansible.builtin.include_tasks: file: tasks/consul/consul_deploy.yml + apply: + tags: + - consul # Vault nodes deployment - name: "Deploy Vault" tags: - vault + - vault_servers when: - enable_vault | bool ansible.builtin.include_tasks: file: tasks/vault/vault_deploy.yml + apply: + tags: + - vault # Nomad nodes deployment - name: "Deploy Nomad" tags: - nomad + - nomad_servers + - nomad_clients when: - enable_nomad | bool ansible.builtin.include_tasks: file: tasks/nomad/nomad_deploy.yml - - # - fail: - # Haproxy nodes deployment - # - name: "Deploy Proxies" - # tags: - # - haproxy - # when: - # - enable_haproxy | bool - # block: - # - name: "Deploy Haproxy & Keepalived" - # ansible.builtin.import_tasks: - # file: tasks/haproxy/haproxy_deploy.yml - # when: - # - "'haproxy_servers' in group_names" + apply: + tags: + - nomad diff --git a/playbooks/group_vars/all/all.yml b/playbooks/group_vars/all/all.yml index 0303894..c03e234 100644 --- a/playbooks/group_vars/all/all.yml +++ b/playbooks/group_vars/all/all.yml @@ -42,3 +42,36 @@ consul_required_ports: [8300, 8301, 8302, 8500, 8501, 8502, 8503, 8600] nomad_required_ports: [4646, 4647, 4648] target: all, !deployment + +############################################################# +# consul -- DO NOT TWEAK UNLESS YOU KNOW WHAT YOU ARE DOING # +############################################################# + +consul_init_server: "{{ (inventory_hostname == groups['consul_servers'][0]) | bool }}" + +consul_api_addr: "{{ consul_api_scheme }}://{{ api_interface_address }}:{{ consul_api_port[consul_api_scheme] }}" +consul_api_scheme: "{{ 'https' if consul_enable_tls else 'http' }}" +consul_api_port: + http: 8500 + https: 8501 +consul_grpc_port: + http: 8502 + https: 8503 + +############################################################ +# nomad -- DO NOT TWEAK UNLESS YOU KNOW WHAT YOU ARE DOING # +############################################################ + +nomad_init_server: "{{ (inventory_hostname == groups['nomad_servers'][0]) | bool }}" + +nomad_api_addr: "{{ nomad_api_scheme }}://{{ api_interface_address }}:{{ nomad_api_port[nomad_api_scheme] }}" +nomad_api_scheme: "{{ 'https' if nomad_enable_tls else 'http' }}" +nomad_api_port: + http: "{{ nomad_address_configuration.ports.http }}" + https: "{{ nomad_address_configuration.ports.http }}" + +############################################################ +# vault -- DO NOT TWEAK UNLESS YOU KNOW WHAT YOU ARE DOING # +############################################################ + +vault_init_server: "{{ (inventory_hostname == groups['vault_servers'][0]) | bool }}" diff --git a/playbooks/group_vars/all/consul.yml b/playbooks/group_vars/all/consul.yml index 918204c..f58de29 100644 --- a/playbooks/group_vars/all/consul.yml +++ b/playbooks/group_vars/all/consul.yml @@ -1,19 +1,4 @@ --- -consul_init_server: "{{ (inventory_hostname == groups['consul_servers'][0]) | bool }}" - -##################### -# consul api config # -##################### - -consul_api_addr: "{{ consul_api_scheme }}://{{ api_interface_address }}:{{ consul_api_port[consul_api_scheme] }}" -consul_api_scheme: "{{ 'https' if consul_enable_tls else 'http' }}" -consul_api_port: - http: 8500 - https: 8501 -consul_grpc_port: - http: 8502 - https: 8503 - ########## # Consul # ########## diff --git a/playbooks/group_vars/all/globals.yml b/playbooks/group_vars/all/globals.yml index 359a20b..0e25e9c 100644 --- a/playbooks/group_vars/all/globals.yml +++ b/playbooks/group_vars/all/globals.yml @@ -3,7 +3,6 @@ # General options # ################### -enable_ingress: "yes" enable_vault: "yes" enable_consul: "yes" enable_nomad: "yes" @@ -16,11 +15,6 @@ consul_fqdn: consul.ednz.lab vault_fqdn: vault.ednz.lab nomad_fqdn: nomad.ednz.lab -# hashistack_external_vip_interface: "eth0" -# hashistack_external_vip_addr: "192.168.121.100" -# hashistack_internal_vip_interface: "{{ hashistack_external_vip_interface }}" -# hashistack_internal_vip_addr: "{{ hashistack_external_vip_addr }}" - api_interface: "eth0" api_interface_address: "{{ ansible_facts[api_interface]['ipv4']['address'] }}" diff --git a/playbooks/group_vars/all/nomad.yml b/playbooks/group_vars/all/nomad.yml index 642228f..376fc0c 100644 --- a/playbooks/group_vars/all/nomad.yml +++ b/playbooks/group_vars/all/nomad.yml @@ -1,16 +1,4 @@ --- -nomad_init_server: "{{ (inventory_hostname == groups['nomad_servers'][0]) | bool }}" - -#################### -# nomad api config # -#################### - -nomad_api_addr: "{{ nomad_api_scheme }}://{{ api_interface_address }}:{{ nomad_api_port[nomad_api_scheme] }}" -nomad_api_scheme: "{{ 'https' if nomad_enable_tls else 'http' }}" -nomad_api_port: - http: "{{ nomad_address_configuration.ports.http }}" - https: "{{ nomad_address_configuration.ports.http }}" - ######### # Nomad # ######### @@ -99,6 +87,12 @@ nomad_client_configuration: cni_path: "{{ cni_plugins_install_path | default('/opt/cni/bin') }}" bridge_network_name: nomad bridge_network_subnet: "172.26.64.0/20" + node_pool: >- + {{ + 'ingress' if 'nomad_ingress' in group_names else + 'controller' if 'nomad_servers' in group_names else + omit + }} #################### # ui configuration # @@ -148,7 +142,7 @@ nomad_acl_configuration: # internal tls # ################ -nomad_enable_tls: false +# nomad_enable_tls: false nomad_tls_configuration: http: true rpc: true diff --git a/playbooks/group_vars/all/vault.yml b/playbooks/group_vars/all/vault.yml index f447156..c5a0f17 100644 --- a/playbooks/group_vars/all/vault.yml +++ b/playbooks/group_vars/all/vault.yml @@ -1,6 +1,4 @@ --- -vault_init_server: "{{ (inventory_hostname == groups['vault_servers'][0]) | bool }}" - ######### # Vault # ######### diff --git a/playbooks/inventory/multinode.ini b/playbooks/inventory/multinode.ini index bf01735..07cb778 100644 --- a/playbooks/inventory/multinode.ini +++ b/playbooks/inventory/multinode.ini @@ -1,7 +1,3 @@ -[haproxy_servers] -haproxy01 -haproxy02 - [vault_servers] vault01 vault02 @@ -25,7 +21,6 @@ nomad-client03 [consul_agents] [consul_agents:children] -haproxy_servers vault_servers nomad_servers nomad_clients @@ -45,7 +40,6 @@ nomad_clients vault_servers [common:children] -haproxy_servers vault_servers consul_servers nomad_servers diff --git a/playbooks/preflight.yml b/playbooks/preflight.yml index 83d076c..92cab07 100644 --- a/playbooks/preflight.yml +++ b/playbooks/preflight.yml @@ -57,27 +57,6 @@ path: "{{ hashistack_configuration_directory }}" register: _stat_config_dir - - name: "Stat nomad_servers config directory" - ansible.builtin.stat: - path: "{{ hashistack_sub_configuration_directories.nomad_servers }}" - register: _stat_config_dir_nomad_servers - when: - - enable_nomad | bool - - - name: "Stat consul_servers config directory" - ansible.builtin.stat: - path: "{{ hashistack_sub_configuration_directories.consul_servers }}" - register: _stat_config_dir_consul_servers - when: - - enable_consul | bool - - - name: "Stat vault_servers config directory" - ansible.builtin.stat: - path: "{{ hashistack_sub_configuration_directories.vault_servers }}" - register: _stat_config_dir_vault_servers - when: - - enable_vault | bool - - name: "Make sure directory exists: {{ hashistack_configuration_directory }}" ansible.builtin.assert: that: @@ -85,33 +64,6 @@ - _stat_config_dir.stat.isdir - _stat_config_dir.stat.writeable - - name: "Make sure directory exists: {{ hashistack_sub_configuration_directories.nomad_servers }}" - ansible.builtin.assert: - that: - - _stat_config_dir_nomad_servers.stat.exists - - _stat_config_dir_nomad_servers.stat.isdir - - _stat_config_dir_nomad_servers.stat.writeable - when: - - enable_nomad | bool - - - name: "Make sure directory exists: {{ hashistack_sub_configuration_directories.consul_servers }}" - ansible.builtin.assert: - that: - - _stat_config_dir_consul_servers.stat.exists - - _stat_config_dir_consul_servers.stat.isdir - - _stat_config_dir_consul_servers.stat.writeable - when: - - enable_consul | bool - - - name: "Make sure directory exists: {{ hashistack_sub_configuration_directories.vault_servers }}" - ansible.builtin.assert: - that: - - _stat_config_dir_vault_servers.stat.exists - - _stat_config_dir_vault_servers.stat.isdir - - _stat_config_dir_vault_servers.stat.writeable - when: - - enable_vault | bool - - name: "Checking host OS distribution" # TODO: This needs to work with debian and ubuntu, major version works for debian but not ubuntu, simple version works the other way around... # ? seems to work diff --git a/playbooks/tasks/nomad/nomad_control_plane.yml b/playbooks/tasks/nomad/nomad_control_plane.yml index da92dfd..87bd79b 100644 --- a/playbooks/tasks/nomad/nomad_control_plane.yml +++ b/playbooks/tasks/nomad/nomad_control_plane.yml @@ -67,15 +67,29 @@ state: present when: _consul_nomad_client_policy.changed - - name: "Include ednz_cloud.hashistack.cni" + - name: "Nomad | Include ednz_cloud.hashistack.cni" ansible.builtin.include_role: name: ednz_cloud.hashistack.cni when: nomad_enable_client - - name: "Include ednz_cloud.hashistack.nomad" + - name: "Nomad | Include ednz_cloud.hashistack.nomad" ansible.builtin.include_role: name: ednz_cloud.hashistack.nomad + - name: "Nomad | Wait for nomad cluster to initialize" + ansible.builtin.uri: + url: "{{ nomad_api_addr }}/v1/status/leader" + return_content: true + validate_certs: false + status_code: + - 200 + until: nomad_api_response.status == 200 + retries: 24 + delay: 5 + register: nomad_api_response + when: + - nomad_init_server + - name: "Nomad | Initialize nomad cluster" # noqa: run-once[task] ednz_cloud.hashistack.nomad_acl_bootstrap: bootstrap_secret: "{{ _credentials.nomad.root_token.secret_id }}" diff --git a/roles/consul/.docsible b/roles/consul/.docsible new file mode 100644 index 0000000..7713e0f --- /dev/null +++ b/roles/consul/.docsible @@ -0,0 +1,13 @@ +aap_hub: null +automation_kind: null +category: null +critical: null +description: null +dt_dev: null +dt_prod: null +dt_update: 26/08/2024 +requester: null +subCategory: null +time_saving: null +users: null +version: null diff --git a/roles/consul/README.md b/roles/consul/README.md new file mode 100644 index 0000000..a644b6b --- /dev/null +++ b/roles/consul/README.md @@ -0,0 +1,227 @@ + + +# πŸ“ƒ Role overview + +## consul + + + +Description: Install and configure hashicorp consul for debian-based distros. + + +| Field | Value | +|--------------------- |-----------------| +| Readme update | 26/08/2024 | + + + + + + +### Defaults + +**These are static variables with lower priority** + +#### File: defaults/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [consul_version](defaults/main.yml#L4) | str | `latest` | n/a | n/a | +| [consul_start_service](defaults/main.yml#L5) | bool | `True` | n/a | n/a | +| [consul_config_dir](defaults/main.yml#L6) | str | `/etc/consul.d` | n/a | n/a | +| [consul_data_dir](defaults/main.yml#L7) | str | `/opt/consul` | n/a | n/a | +| [consul_certs_dir](defaults/main.yml#L8) | str | `{{ consul_config_dir }}/tls` | n/a | n/a | +| [consul_logs_dir](defaults/main.yml#L9) | str | `/var/log/consul` | n/a | n/a | +| [consul_envoy_install](defaults/main.yml#L11) | bool | `False` | n/a | n/a | +| [consul_envoy_version](defaults/main.yml#L12) | str | `latest` | n/a | n/a | +| [consul_extra_files](defaults/main.yml#L14) | bool | `False` | n/a | n/a | +| [consul_extra_files_list](defaults/main.yml#L15) | list | `[]` | n/a | n/a | +| [consul_env_variables](defaults/main.yml#L17) | dict | `{}` | n/a | n/a | +| [consul_extra_configuration](defaults/main.yml#L28) | dict | `{}` | n/a | n/a | +| [consul_domain](defaults/main.yml#L34) | str | `consul` | n/a | n/a | +| [consul_datacenter](defaults/main.yml#L35) | str | `dc1` | n/a | n/a | +| [consul_primary_datacenter](defaults/main.yml#L36) | str | `{{ consul_datacenter }}` | n/a | n/a | +| [consul_gossip_encryption_key](defaults/main.yml#L37) | str | `{{ 'mysupersecretgossipencryptionkey'\|b64encode }}` | n/a | n/a | +| [consul_enable_script_checks](defaults/main.yml#L38) | bool | `False` | n/a | n/a | +| [consul_leave_on_terminate](defaults/main.yml#L44) | bool | `True` | n/a | n/a | +| [consul_rejoin_after_leave](defaults/main.yml#L45) | bool | `True` | n/a | n/a | +| [consul_join_configuration](defaults/main.yml#L51) | dict | `{'retry_join': ['{{ ansible_default_ipv4.address }}'], 'retry_interval': '30s', 'retry_max': 0}` | n/a | n/a | +| [consul_enable_server](defaults/main.yml#L61) | bool | `True` | n/a | n/a | +| [consul_bootstrap_expect](defaults/main.yml#L62) | int | `1` | n/a | n/a | +| [consul_ui_configuration](defaults/main.yml#L68) | dict | `{'enabled': '{{ consul_enable_server }}'}` | n/a | n/a | +| [consul_bind_addr](defaults/main.yml#L75) | str | `0.0.0.0` | n/a | n/a | +| [consul_advertise_addr](defaults/main.yml#L76) | str | `{{ ansible_default_ipv4.address }}` | n/a | n/a | +| [consul_address_configuration](defaults/main.yml#L77) | dict | `{'client_addr': '{{ consul_bind_addr }}', 'bind_addr': '{{ consul_advertise_addr }}', 'advertise_addr': '{{ consul_advertise_addr }}'}` | n/a | n/a | +| [consul_acl_configuration](defaults/main.yml#L86) | dict | `{'enabled': False, 'default_policy': 'deny', 'enable_token_persistence': True}` | n/a | n/a | +| [consul_mesh_configuration](defaults/main.yml#L97) | dict | `{'enabled': False}` | n/a | n/a | +| [consul_dns_configuration](defaults/main.yml#L104) | dict | `{'allow_stale': True, 'enable_truncate': True, 'only_passing': True}` | n/a | n/a | +| [consul_enable_tls](defaults/main.yml#L113) | bool | `False` | n/a | n/a | +| [consul_tls_configuration](defaults/main.yml#L114) | dict | `{'defaults': {'ca_file': '/etc/ssl/certs/ca-certificates.crt', 'cert_file': '{{ consul_certs_dir }}/cert.pem', 'key_file': '{{ consul_certs_dir }}/key.pem', 'verify_incoming': False, 'verify_outgoing': True}, 'internal_rpc': {'verify_server_hostname': True}}` | n/a | n/a | +| [consul_certificates_extra_files_dir](defaults/main.yml#L124) | list | `[]` | n/a | n/a | +| [consul_enable_prometheus_metrics](defaults/main.yml#L133) | bool | `False` | n/a | n/a | +| [consul_prometheus_retention_time](defaults/main.yml#L134) | str | `60s` | n/a | n/a | +| [consul_telemetry_configuration](defaults/main.yml#L135) | dict | `{}` | n/a | n/a | +| [consul_log_level](defaults/main.yml#L141) | str | `info` | n/a | n/a | +| [consul_enable_log_to_file](defaults/main.yml#L142) | bool | `False` | n/a | n/a | +| [consul_log_to_file_configuration](defaults/main.yml#L143) | dict | `{'log_file': '{{ consul_logs_dir }}/consul.log', 'log_rotate_duration': '24h', 'log_rotate_max_files': 30}` | n/a | n/a | + + +### Vars + +**These are variables with higher priority** +#### File: vars/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [consul_user](vars/main.yml#L3) | str | `consul` | n/a | n/a | +| [consul_group](vars/main.yml#L4) | str | `consul` | n/a | n/a | +| [consul_binary_path](vars/main.yml#L5) | str | `/usr/local/bin/consul` | n/a | n/a | +| [consul_envoy_binary_path](vars/main.yml#L6) | str | `/usr/local/bin/envoy` | n/a | n/a | +| [consul_deb_architecture_map](vars/main.yml#L7) | dict | `{'x86_64': 'amd64', 'aarch64': 'arm64', 'armv7l': 'arm', 'armv6l': 'arm'}` | n/a | n/a | +| [consul_envoy_architecture_map](vars/main.yml#L12) | dict | `{'x86_64': 'x86_64', 'aarch64': 'aarch64'}` | n/a | n/a | +| [consul_architecture](vars/main.yml#L15) | str | `{{ consul_deb_architecture_map[ansible_architecture] \| default(ansible_architecture) }}` | n/a | n/a | +| [consul_envoy_architecture](vars/main.yml#L16) | str | `{{ consul_envoy_architecture_map[ansible_architecture] \| default(ansible_architecture) }}` | n/a | n/a | +| [consul_service_name](vars/main.yml#L17) | str | `consul` | n/a | n/a | +| [consul_github_api](vars/main.yml#L18) | str | `https://api.github.com/repos` | n/a | n/a | +| [consul_envoy_github_project](vars/main.yml#L19) | str | `envoyproxy/envoy` | n/a | n/a | +| [consul_github_project](vars/main.yml#L20) | str | `hashicorp/consul` | n/a | n/a | +| [consul_github_url](vars/main.yml#L21) | str | `https://github.com` | n/a | n/a | +| [consul_repository_url](vars/main.yml#L22) | str | `https://releases.hashicorp.com/consul` | n/a | n/a | +| [consul_configuration](vars/main.yml#L24) | dict | `{'domain': '{{ consul_domain }}', 'datacenter': '{{ consul_datacenter }}', 'primary_datacenter': '{{ consul_primary_datacenter }}', 'data_dir': '{{ consul_data_dir }}', 'encrypt': '{{ consul_gossip_encryption_key }}', 'server': '{{ consul_enable_server }}', 'ui_config': '{{ consul_ui_configuration }}', 'connect': '{{ consul_mesh_configuration }}', 'leave_on_terminate': '{{ consul_leave_on_terminate }}', 'rejoin_after_leave': '{{ consul_rejoin_after_leave }}', 'enable_script_checks': '{{ consul_enable_script_checks }}', 'enable_syslog': True, 'acl': '{{ consul_acl_configuration }}', 'dns_config': '{{ consul_dns_configuration }}', 'log_level': '{{ consul_log_level }}', 'ports': {'dns': 8600, 'server': 8300, 'serf_lan': 8301, 'serf_wan': 8302, 'sidecar_min_port': 21000, 'sidecar_max_port': 21255, 'expose_min_port': 21500, 'expose_max_port': 21755}}` | n/a | n/a | +| [consul_configuration_string](vars/main.yml#L50) | str | `` | n/a | n/a | +| [consul_server_configuration_string](vars/main.yml#L57) | str | `` | n/a | n/a | + + +### Tasks + + +#### File: tasks/recursive_copy_extra_dirs.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul \| Ensure destination directory exists | ansible.builtin.file | False | +| Consul \| Create extra directory sources | ansible.builtin.file | True | +| Consul \| Template extra directory sources | ansible.builtin.template | True | + +#### File: tasks/merge_variables.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul \| Merge stringified configuration | vars | False | +| Consul \| Merge server specific stringified configuration | vars | True | +| Consul \| Merge join configuration | vars | False | +| Consul \| Merge addresses configuration | vars | False | +| Consul \| Merge TLS configuration | block | True | +| Consul \| Merge TLS configuration | vars | False | +| Consul \| Add certificates directory to extra_files_dir | ansible.builtin.set_fact | False | +| Consul \| Merge extra configuration settings | vars | False | +| Consul \| Merge log to file configuration | vars | True | +| Consul \| Merge telemetry configuration | block | False | +| Consul \| Merge prometheus metrics configuration | vars | True | +| Consul \| Merge telemtry configuration | vars | False | + +#### File: tasks/main.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul \| Set reload-check & restart-check variable | ansible.builtin.set_fact | False | +| Consul \| Import merge_variables.yml | ansible.builtin.include_tasks | False | +| Consul \| Import prerequisites.yml | ansible.builtin.include_tasks | False | +| Consul \| Import install_envoy.yml | ansible.builtin.include_tasks | True | +| Consul \| Import install.yml | ansible.builtin.include_tasks | False | +| Consul \| Import configure.yml | ansible.builtin.include_tasks | False | +| Consul \| Populate service facts | ansible.builtin.service_facts | False | +| Consul \| Set restart-check variable | ansible.builtin.set_fact | True | +| Consul \| Enable service: {{ consul_service_name }} | ansible.builtin.service | False | +| Consul \| Reload systemd daemon | ansible.builtin.systemd | True | +| Consul \| Start service: {{ consul_service_name }} | ansible.builtin.service | True | + +#### File: tasks/install.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul \| Get latest release of consul | block | True | +| Consul \| Get latest consul release from github api | ansible.builtin.uri | False | +| Consul \| Set wanted consul version to latest tag | ansible.builtin.set_fact | False | +| Consul \| Set wanted consul version to {{ consul_version }} | ansible.builtin.set_fact | True | +| Consul \| Get current consul version | block | False | +| Consul \| Stat consul version file | ansible.builtin.stat | False | +| Consul \| Get current consul version | ansible.builtin.slurp | True | +| Consul \| Download and install consul binary | block | True | +| Consul \| Set consul package name to download | ansible.builtin.set_fact | False | +| Consul \| Download checksum file for consul archive | ansible.builtin.get_url | False | +| Consul \| Extract correct checksum from checksum file | ansible.builtin.command | False | +| Consul \| Parse the expected checksum | ansible.builtin.set_fact | False | +| Consul \| Download consul binary archive | ansible.builtin.get_url | False | +| Consul \| Create temporary directory for archive decompression | ansible.builtin.file | False | +| Consul \| Unpack consul archive | ansible.builtin.unarchive | False | +| Consul \| Copy consul binary to {{ consul_binary_path }} | ansible.builtin.copy | False | +| Consul \| Update consul version file | ansible.builtin.copy | False | +| Consul \| Set restart-check variable | ansible.builtin.set_fact | False | +| Consul \| Cleanup temporary directory | ansible.builtin.file | False | +| Consul \| Copy systemd service file for consul | ansible.builtin.template | False | +| Consul \| Set reload-check & restart-check variable | ansible.builtin.set_fact | True | + +#### File: tasks/install_envoy.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul \| Get release for envoy:{{ consul_envoy_version }} | vars | False | +| Consul \| Check if envoy is already installed | ansible.builtin.stat | False | +| Consul \| Check current envoy version | ansible.builtin.command | True | +| Consul \| Set facts for wanted envoy release | ansible.builtin.set_fact | True | +| Consul \| Set facts for current envoy release | ansible.builtin.set_fact | True | +| Consul \| Create envoy directory | ansible.builtin.file | False | +| Consul \| Install envoy | block | True | +| Consul \| Remove old compose binary if different | ansible.builtin.file | False | +| Consul \| Download and install envoy version:{{ consul_envoy_version }} | ansible.builtin.get_url | False | +| Consul \| Update version file | ansible.builtin.copy | False | + +#### File: tasks/prerequisites.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul \| Create group {{ consul_group }} | ansible.builtin.group | False | +| Consul \| Create user {{ consul_user }} | ansible.builtin.user | False | +| Consul \| Create directory {{ consul_config_dir }} | ansible.builtin.file | False | +| Consul \| Create directory {{ consul_data_dir}} | ansible.builtin.file | False | +| Consul \| Create directory {{ consul_certs_dir }} | ansible.builtin.file | False | +| Consul \| Create directory {{ consul_logs_dir }} | ansible.builtin.file | True | + +#### File: tasks/configure.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul \| Create consul.env | ansible.builtin.template | False | +| Consul \| Copy consul.json template | ansible.builtin.template | False | +| Consul \| Set restart-check variable | ansible.builtin.set_fact | True | +| Consul \| Copy extra configuration files | block | True | +| Consul \| Get extra file types | ansible.builtin.stat | False | +| Consul \| Set list for file sources | vars | True | +| Consul \| Set list for directory sources | vars | True | +| Consul \| Template extra file sources | ansible.builtin.template | True | +| Consul \| Template extra directory sources | ansible.builtin.include_tasks | True | + + + + + + + +## Author Information +Bertrand Lanson + +#### License + +license (BSD, MIT) + +#### Minimum Ansible Version + +2.10 + +#### Platforms + +- **Ubuntu**: ['focal', 'jammy', 'noble'] +- **Debian**: ['bullseye', 'bookworm'] + + diff --git a/roles/hashistack/.docsible b/roles/hashistack/.docsible new file mode 100644 index 0000000..7713e0f --- /dev/null +++ b/roles/hashistack/.docsible @@ -0,0 +1,13 @@ +aap_hub: null +automation_kind: null +category: null +critical: null +description: null +dt_dev: null +dt_prod: null +dt_update: 26/08/2024 +requester: null +subCategory: null +time_saving: null +users: null +version: null diff --git a/roles/hashistack/README.md b/roles/hashistack/README.md new file mode 100644 index 0000000..2f6bb8b --- /dev/null +++ b/roles/hashistack/README.md @@ -0,0 +1,123 @@ + + +# πŸ“ƒ Role overview + +## hashistack + + + +Description: Merge variables for the playbooks contained in ednz_cloud.hashistack collection + + +| Field | Value | +|--------------------- |-----------------| +| Readme update | 26/08/2024 | + + + + + + +### Defaults + +**These are static variables with lower priority** + +#### File: defaults/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [hashistack_configuration_directory](defaults/main.yml#L3) | str | `{{ lookup('env', 'PWD') }}/etc/hashistack` | n/a | n/a | +| [hashistack_sub_configuration_directories](defaults/main.yml#L4) | dict | `{'secrets': '{{ hashistack_configuration_directory }}/secrets', 'certificates': '{{ hashistack_configuration_directory }}/certificates', 'nomad_servers': '{{ hashistack_configuration_directory }}/nomad_servers', 'vault_servers': '{{ hashistack_configuration_directory }}/vault_servers', 'consul_servers': '{{ hashistack_configuration_directory }}/consul_servers'}` | n/a | n/a | +| [hashistack_configuration_global_vars_file](defaults/main.yml#L11) | str | `globals.yml` | n/a | n/a | +| [hashistack_configuration_credentials_vars_file](defaults/main.yml#L12) | str | `credentials.yml` | n/a | n/a | +| [hashistack_remote_config_dir](defaults/main.yml#L14) | str | `/etc/hashistack` | n/a | n/a | +| [hashistack_remote_log_dir](defaults/main.yml#L15) | str | `/var/log/hashistack` | n/a | n/a | +| [hashistack_only_load_credentials](defaults/main.yml#L17) | bool | `False` | n/a | n/a | + + + + + +### Tasks + + +#### File: tasks/load_group_vars.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Variables \| Stat group specific config file | ansible.builtin.stat | False | +| Variables \| Load group specific variables | ansible.builtin.include_vars | True | + +#### File: tasks/load_credentials_vars.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Variables \| Stat credentials file | ansible.builtin.stat | False | +| Variables \| Stat vault credentials file | ansible.builtin.stat | False | +| Variables \| Make sure credentials file exists | ansible.builtin.assert | False | +| Variables \| Load credentials variables | ansible.builtin.include_vars | False | +| Variables \| Load vault credentials if vault.yml exists | ansible.builtin.include_vars | True | +| Variables \| Merge vault credentials into _credentials | vars | True | + +#### File: tasks/load_host_vars.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Variables \| Stat host specific config file | ansible.builtin.stat | False | +| Variables \| Load host specific variables | ansible.builtin.include_vars | True | + +#### File: tasks/main.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Variables \| Load global variables | ansible.builtin.include_tasks | True | +| Variables \| Load credentials variables | ansible.builtin.include_tasks | False | +| Variables \| Load group specific variables | ansible.builtin.include_tasks | True | +| Variables \| Load host specific variables | ansible.builtin.include_tasks | True | +| Ensure remote directories exists | ansible.builtin.file | True | +| Variables \| Load custom CA certificates | ansible.builtin.include_tasks | True | + +#### File: tasks/load_ca_certificates.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Check if CA directory exists | ansible.builtin.stat | False | +| Find custom ca certificates to copy | ansible.builtin.find | True | +| Ensure remote ca directory exists | ansible.builtin.file | False | +| Copy custom ca certificates | ansible.builtin.copy | True | +| Copy and update trust store | block | True | +| Copy ca certificates to /usr/local/share/ca-certificates | ansible.builtin.file | False | +| Update the trust store | ansible.builtin.command | True | + +#### File: tasks/load_global_vars.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Variables \| Include all default variables | ansible.builtin.include_vars | False | +| Variables \| Stat global configuration file | ansible.builtin.stat | False | +| Variables \| Make sure global configuration file exists | ansible.builtin.assert | False | +| Variables \| Load global variables | ansible.builtin.include_vars | False | + + + + + + + +## Author Information +Bertrand Lanson + +#### License + +license (BSD, MIT) + +#### Minimum Ansible Version + +2.10 + +#### Platforms + +- **Ubuntu**: ['focal', 'jammy', 'noble'] +- **Debian**: ['bullseye', 'bookworm'] + + diff --git a/roles/hashistack_ca/.docsible b/roles/hashistack_ca/.docsible new file mode 100644 index 0000000..7713e0f --- /dev/null +++ b/roles/hashistack_ca/.docsible @@ -0,0 +1,13 @@ +aap_hub: null +automation_kind: null +category: null +critical: null +description: null +dt_dev: null +dt_prod: null +dt_update: 26/08/2024 +requester: null +subCategory: null +time_saving: null +users: null +version: null diff --git a/roles/hashistack_ca/README.md b/roles/hashistack_ca/README.md new file mode 100644 index 0000000..08e3d09 --- /dev/null +++ b/roles/hashistack_ca/README.md @@ -0,0 +1,313 @@ + + +# πŸ“ƒ Role overview + +## hashistack_ca + + + + +Description: Not available. + +| Field | Value | +|--------------------- |-----------------| +| Readme update | 26/08/2024 | + + + + + + +### Defaults + +**These are static variables with lower priority** + +#### File: defaults/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [hashistack_ca_directory](defaults/main.yml#L3) | str | `/etc/hashistack/certificates` | n/a | n/a | +| [hashistack_ca_use_cryptography](defaults/main.yml#L4) | bool | `False` | n/a | n/a | +| [hashistack_ca_action](defaults/main.yml#L5) | str | `noop` | n/a | n/a | +| [hashistack_ca_domain](defaults/main.yml#L6) | str | `example.com` | n/a | n/a | +| [hashistack_ca_directory_owner](defaults/main.yml#L7) | str | `root` | n/a | n/a | +| [hashistack_ca_root_org_name](defaults/main.yml#L12) | str | `EDNZ Cloud` | n/a | n/a | +| [hashistack_ca_root_country](defaults/main.yml#L13) | str | `FR` | n/a | n/a | +| [hashistack_ca_root_locality](defaults/main.yml#L14) | str | `Paris` | n/a | n/a | +| [hashistack_ca_root_common_name](defaults/main.yml#L15) | str | `{{ hashistack_ca_domain }} Root CA` | n/a | n/a | +| [hashistack_ca_root_email](defaults/main.yml#L16) | NoneType | `None` | n/a | n/a | +| [hashistack_ca_root_key_usage](defaults/main.yml#L17) | list | `['keyCertSign', 'cRLSign']` | n/a | n/a | +| [hashistack_ca_root_key_usage_critical](defaults/main.yml#L20) | bool | `True` | n/a | n/a | +| [hashistack_ca_root_basic_constraints](defaults/main.yml#L21) | list | `['CA:TRUE']` | n/a | n/a | +| [hashistack_ca_root_basic_constraints_critical](defaults/main.yml#L23) | bool | `True` | n/a | n/a | +| [hashistack_ca_root_state_or_province_name](defaults/main.yml#L26) | NoneType | `None` | n/a | n/a | +| [hashistack_ca_root_email_address](defaults/main.yml#L27) | NoneType | `None` | n/a | n/a | +| [hashistack_ca_root_valid_for](defaults/main.yml#L30) | str | `1825d` | n/a | n/a | +| [hashistack_ca_root_renew_threshold](defaults/main.yml#L31) | str | `180d` | n/a | n/a | +| [hashistack_ca_intermediate_org_name](defaults/main.yml#L36) | str | `EDNZ Cloud Intermediate` | n/a | n/a | +| [hashistack_ca_intermediate_country](defaults/main.yml#L37) | str | `FR` | n/a | n/a | +| [hashistack_ca_intermediate_locality](defaults/main.yml#L38) | str | `Paris` | n/a | n/a | +| [hashistack_ca_intermediate_common_name](defaults/main.yml#L39) | str | `{{ hashistack_ca_domain }} Intermediate CA` | n/a | n/a | +| [hashistack_ca_intermediate_email](defaults/main.yml#L40) | NoneType | `None` | n/a | n/a | +| [hashistack_ca_intermediate_key_usage](defaults/main.yml#L41) | list | `['keyCertSign', 'cRLSign']` | n/a | n/a | +| [hashistack_ca_intermediate_key_usage_critical](defaults/main.yml#L44) | bool | `True` | n/a | n/a | +| [hashistack_ca_intermediate_basic_constraints](defaults/main.yml#L45) | list | `['CA:TRUE', 'pathlen:0']` | n/a | n/a | +| [hashistack_ca_intermediate_basic_constraints_critical](defaults/main.yml#L48) | bool | `True` | n/a | n/a | +| [hashistack_ca_intermediate_state_or_province_name](defaults/main.yml#L51) | NoneType | `None` | n/a | n/a | +| [hashistack_ca_intermediate_email_address](defaults/main.yml#L52) | NoneType | `None` | n/a | n/a | +| [hashistack_ca_intermediate_valid_for](defaults/main.yml#L55) | str | `365d` | n/a | n/a | +| [hashistack_ca_intermediate_renew_threshold](defaults/main.yml#L56) | str | `90d` | n/a | n/a | +| [hashistack_ca_intermediate_name_constraints_permitted](defaults/main.yml#L59) | list | `['DNS:.{{ hashistack_ca_domain }}', 'DNS:.nomad', 'DNS:.consul', 'DNS:localhost', 'IP:192.168.0.0/16', 'IP:172.16.0.0/16', 'IP:10.0.0.0/8', 'IP:127.0.0.0/8']` | n/a | n/a | +| [hashistack_ca_intermediate_name_constraints_critical](defaults/main.yml#L68) | str | `{{ (hashistack_ca_intermediate_name_constraints_permitted is defined and hashistack_ca_intermediate_name_constraints_permitted \| length > 0) }}` | n/a | n/a | +| [hashistack_ca_leaf_valid_for](defaults/main.yml#L74) | str | `90d` | n/a | n/a | +| [hashistack_ca_leaf_renew_threshold](defaults/main.yml#L75) | str | `30d` | n/a | n/a | +| [hashistack_ca_consul_org_name](defaults/main.yml#L80) | str | `{{ hashistack_ca_root_org_name }}` | n/a | n/a | +| [hashistack_ca_consul_common_name](defaults/main.yml#L81) | str | `{{ inventory_hostname }}` | n/a | n/a | +| [hashistack_ca_consul_csr_sans](defaults/main.yml#L82) | list | `['DNS:consul.service.consul', 'DNS:localhost', 'IP:127.0.0.1']` | n/a | n/a | +| [hashistack_ca_nomad_org_name](defaults/main.yml#L90) | str | `{{ hashistack_ca_root_org_name }}` | n/a | n/a | +| [hashistack_ca_nomad_common_name](defaults/main.yml#L91) | str | `{{ inventory_hostname }}` | n/a | n/a | +| [hashistack_ca_nomad_csr_sans](defaults/main.yml#L92) | list | `['DNS:server.global.nomad', 'DNS:client.global.nomad', 'DNS:nomad.service.consul', 'DNS:localhost', 'IP:127.0.0.1']` | n/a | n/a | +| [hashistack_ca_vault_org_name](defaults/main.yml#L102) | str | `{{ hashistack_ca_root_org_name }}` | n/a | n/a | +| [hashistack_ca_vault_common_name](defaults/main.yml#L103) | str | `{{ inventory_hostname }}` | n/a | n/a | +| [hashistack_ca_vault_csr_sans](defaults/main.yml#L104) | list | `['DNS:vault.service.consul', 'DNS:active.vault.service.consul', 'DNS:standby.vault.service.consul', 'DNS:localhost', 'IP:127.0.0.1']` | n/a | n/a | + + +### Vars + +**These are variables with higher priority** +#### File: vars/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [hashistack_ca_action_list](vars/main.yml#L3) | str | `{{ hashistack_ca_action.split(',') }}` | n/a | n/a | +| [hashistack_ca_generate_root](vars/main.yml#L6) | str | `{{ 'root_ca' in hashistack_ca_action_list }}` | n/a | n/a | +| [hashistack_ca_generate_intermediate](vars/main.yml#L7) | str | `{{ 'int_ca' in hashistack_ca_action_list }}` | n/a | n/a | +| [hashistack_ca_generate_leaf](vars/main.yml#L8) | str | `{{ 'leaf_cert' in hashistack_ca_action_list }}` | n/a | n/a | +| [hashistack_ca_renew_root](vars/main.yml#L9) | str | `{{ 'renew_root' in hashistack_ca_action_list }}` | n/a | n/a | +| [hashistack_ca_renew_intermediate](vars/main.yml#L10) | str | `{{ 'renew_int' in hashistack_ca_action_list }}` | n/a | n/a | +| [hashistack_ca_renew_leaf](vars/main.yml#L11) | str | `{{ 'renew_leaf' in hashistack_ca_action_list }}` | n/a | n/a | +| [hashistack_ca_public_dir](vars/main.yml#L13) | str | `{{ hashistack_ca_directory }}/ca` | n/a | n/a | +| [hashistack_ca_root_dir](vars/main.yml#L15) | str | `{{ hashistack_ca_directory }}/root` | n/a | n/a | +| [hashistack_ca_root_backup_dir](vars/main.yml#L16) | str | `{{ hashistack_ca_root_dir }}/backup` | n/a | n/a | +| [hashistack_ca_root_key_path](vars/main.yml#L17) | str | `{{ hashistack_ca_root_dir }}/ca.key` | n/a | n/a | +| [hashistack_ca_root_cert_path](vars/main.yml#L18) | str | `{{ hashistack_ca_root_dir }}/ca.crt` | n/a | n/a | +| [hashistack_ca_intermediate_dir](vars/main.yml#L20) | str | `{{ hashistack_ca_directory }}/intermediate` | n/a | n/a | +| [hashistack_ca_intermediate_backup_dir](vars/main.yml#L21) | str | `{{ hashistack_ca_intermediate_dir }}/backup` | n/a | n/a | +| [hashistack_ca_intermediate_key_path](vars/main.yml#L22) | str | `{{ hashistack_ca_intermediate_dir }}/ca.key` | n/a | n/a | +| [hashistack_ca_intermediate_csr_path](vars/main.yml#L23) | str | `{{ hashistack_ca_intermediate_dir }}/ca.csr` | n/a | n/a | +| [hashistack_ca_intermediate_cert_path](vars/main.yml#L24) | str | `{{ hashistack_ca_intermediate_dir }}/ca.crt` | n/a | n/a | +| [hashistack_ca_consul_dir](vars/main.yml#L26) | str | `{{ hashistack_ca_directory }}/consul/{{ inventory_hostname }}` | n/a | n/a | +| [hashistack_ca_consul_key_path](vars/main.yml#L27) | str | `{{ hashistack_ca_consul_dir }}/cert.key` | n/a | n/a | +| [hashistack_ca_consul_cert_path](vars/main.yml#L28) | str | `{{ hashistack_ca_consul_dir }}/cert.crt` | n/a | n/a | +| [hashistack_ca_consul_fullchain_path](vars/main.yml#L29) | str | `{{ hashistack_ca_consul_dir }}/fullchain.crt` | n/a | n/a | +| [hashistack_ca_nomad_dir](vars/main.yml#L31) | str | `{{ hashistack_ca_directory }}/nomad/{{ inventory_hostname }}` | n/a | n/a | +| [hashistack_ca_nomad_key_path](vars/main.yml#L32) | str | `{{ hashistack_ca_nomad_dir }}/cert.key` | n/a | n/a | +| [hashistack_ca_nomad_cert_path](vars/main.yml#L33) | str | `{{ hashistack_ca_nomad_dir }}/cert.crt` | n/a | n/a | +| [hashistack_ca_nomad_fullchain_path](vars/main.yml#L34) | str | `{{ hashistack_ca_nomad_dir }}/fullchain.crt` | n/a | n/a | +| [hashistack_ca_vault_dir](vars/main.yml#L36) | str | `{{ hashistack_ca_directory }}/vault/{{ inventory_hostname }}` | n/a | n/a | +| [hashistack_ca_vault_key_path](vars/main.yml#L37) | str | `{{ hashistack_ca_vault_dir }}/cert.key` | n/a | n/a | +| [hashistack_ca_vault_cert_path](vars/main.yml#L38) | str | `{{ hashistack_ca_vault_dir }}/cert.crt` | n/a | n/a | +| [hashistack_ca_vault_fullchain_path](vars/main.yml#L39) | str | `{{ hashistack_ca_vault_dir }}/fullchain.crt` | n/a | n/a | + + +### Tasks + + +#### File: tasks/prepare_ca_to_copy.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| CA \| Check if CA directory exists | ansible.builtin.stat | False | +| CA \| Find custom CA certificates to copy | ansible.builtin.find | True | +| CA \| Ensure public CA directory exists | ansible.builtin.file | False | +| CA \| Copy root CA certificates | ansible.builtin.copy | True | + +#### File: tasks/main.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| CA \| Import generate_root.yml | ansible.builtin.include_tasks | True | +| CA \| Import generate_intermediate.yml | ansible.builtin.include_tasks | True | +| CA \| Import renew_root.yml | ansible.builtin.include_tasks | True | +| CA \| Import renew_intermediate.yml | ansible.builtin.include_tasks | True | +| CA \| Import prepare_ca_to_copy.yml | ansible.builtin.include_tasks | False | +| CA \| Import cleanup_backups.yml | ansible.builtin.include_tasks | False | +| Consul leaf certificates \| Import generate/generate_consul.yml | ansible.builtin.include_tasks | True | +| Nomad leaf certificates \| Import generate/generate_nomad.yml | ansible.builtin.include_tasks | True | +| Vault leaf certificates \| Import generate/generate_vault.yml | ansible.builtin.include_tasks | True | +| Consul leaf certificates \| Import renew_consul.yml | ansible.builtin.include_tasks | True | + +#### File: tasks/cleanup_backups.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Cleanup \| Check if root CA backup directory exists | ansible.builtin.stat | False | +| Cleanup \| Check if intermediate CA backup directory exists | ansible.builtin.stat | False | +| Cleanup \| Root CA backups | block | True | +| Root CA \| Find root CA backup certificates | ansible.builtin.find | False | +| Root CA \| Check expiration for root CA backup certificates | when | True | +| Root CA \| Remove expired root CA backup certificates | when | True | +| Cleanup \| Intermediate CA backups | block | True | +| Intermediate CA \| Find intermediate CA backup certificates | ansible.builtin.find | False | +| Intermediate CA \| Check expiration for intermediate CA backup certificates | when | True | +| Intermediate CA \| Remove expired intermediate CA backup certificates | when | True | + +#### File: tasks/generate/generate_consul.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul leaf certificates \| Create certificate directory in for consul servers | ansible.builtin.file | False | +| Consul leaf certificates \| Create Consul certificates | block | False | +| Consul leaf certificates \| Create Consul certificate keys | community.crypto.openssl_privatekey | False | +| Consul leaf certificates \| Create CSRs for Consul servers | community.crypto.openssl_csr_pipe | False | +| Consul leaf certificates \| Sign certificates with internal CA | community.crypto.x509_certificate | False | +| Consul leaf certificates \| Generate fullchain certificate | block | False | +| Consul leaf certificates \| Read content of root ca certificate | ansible.builtin.slurp | False | +| Consul leaf certificates \| Read content of intermediate ca certificate | ansible.builtin.slurp | False | +| Consul leaf certificates \| Read content of leaf certificate | ansible.builtin.slurp | False | +| Consul leaf certificates \| Concatenate certificates | ansible.builtin.copy | False | + +#### File: tasks/generate/generate_intermediate.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Intermediate CA \| Create temporary cert directory in {{ hashistack_ca_directory }}/intermediate | ansible.builtin.file | False | +| Intermediate CA \| Generate internal certificates | block | False | +| Intermediate CA \| Create intermediate CA private key | community.crypto.openssl_privatekey | False | +| Intermediate CA \| Create intermediate CA signing request | community.crypto.openssl_csr_pipe | False | +| Intermediate CA \| Create signed intermediate CA certificate from CSR | community.crypto.x509_certificate | False | + +#### File: tasks/generate/generate_nomad.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Nomad leaf certificates \| Create certificate directory in for nomad servers | ansible.builtin.file | False | +| Nomad leaf certificates \| Create Nomad certificates | block | False | +| Nomad leaf certificates \| Create Nomad certificate keys | community.crypto.openssl_privatekey | False | +| Nomad leaf certificates \| Create CSRs for Nomad servers | community.crypto.openssl_csr_pipe | False | +| Nomad leaf certificates \| Sign certificates with internal CA | community.crypto.x509_certificate | False | +| Nomad leaf certificates \| Generate fullchain certificate | block | False | +| Nomad leaf certificates \| Read content of root ca certificate | ansible.builtin.slurp | False | +| Nomad leaf certificates \| Read content of intermediate ca certificate | ansible.builtin.slurp | False | +| Nomad leaf certificates \| Read content of leaf certificate | ansible.builtin.slurp | False | +| Nomad leaf certificates \| Concatenate certificates | ansible.builtin.copy | False | + +#### File: tasks/generate/generate_vault.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Vault leaf certificates \| Create certificate directory in for vault servers | ansible.builtin.file | False | +| Vault leaf certificates \| Create Vault certificates | block | False | +| Vault leaf certificates \| Create Vault certificate keys | community.crypto.openssl_privatekey | False | +| Vault leaf certificates \| Create CSRs for Vault servers | community.crypto.openssl_csr_pipe | False | +| Vault leaf certificates \| Sign certificates with internal CA | community.crypto.x509_certificate | False | +| Vault leaf certificates \| Generate fullchain certificate | block | False | +| Vault leaf certificates \| Read content of root ca certificate | ansible.builtin.slurp | False | +| Vault leaf certificates \| Read content of intermediate ca certificate | ansible.builtin.slurp | False | +| Vault leaf certificates \| Read content of leaf certificate | ansible.builtin.slurp | False | +| Vault leaf certificates \| Concatenate certificates | ansible.builtin.copy | False | + +#### File: tasks/generate/generate_root.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Root CA \| Create temporary cert directory in {{ hashistack_ca_directory }} | ansible.builtin.file | False | +| Root CA \| Generate root Authority | block | False | +| Root CA \| Create CA private key | community.crypto.openssl_privatekey | False | +| Root CA \| Create CA signing request | community.crypto.openssl_csr_pipe | False | +| Root CA \| Create self-signed CA certificate from CSR | community.crypto.x509_certificate | False | +| Root CA \| Create self-signed CA certificate from CSR | community.crypto.x509_certificate | False | + +#### File: tasks/renew/renew_root.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Root CA \| Check if root CA certificate exists | ansible.builtin.stat | False | +| Root CA \| Check CA for renewal | block | True | +| Root CA \| Get root CA certificate expiration date | community.crypto.x509_certificate_info | False | +| Root CA \| Check if root CA certificate is expiring within the threshold | ansible.builtin.set_fact | False | +| Root CA \| Renew CA if expiring soon | block | True | +| Root CA \| Create backup directory for root CA | ansible.builtin.file | False | +| Root CA \| Format expiration date for backup | ansible.builtin.set_fact | False | +| Root CA \| Rename existing root CA certificate | ansible.builtin.command | False | +| Root CA \| Remove existing root CA key | ansible.builtin.file | False | +| Root CA \| Generate new root CA if renaming was successful | ansible.builtin.include_tasks | False | +| Root CA \| Generate new intermediate CA | ansible.builtin.include_tasks | False | + +#### File: tasks/renew/renew_consul.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Consul leaf certificates \| Check if certificate exists | ansible.builtin.stat | False | +| Consul leaf certificates \| Check if intermediate CA certificate exists | ansible.builtin.stat | False | +| Consul leaf certificates \| Check certificate for renewal | block | True | +| Consul leaf certificates \| Get certificate expiration date | community.crypto.x509_certificate_info | False | +| Intermediate CA \| Get intermediate CA certificate info | community.crypto.x509_certificate_info | False | +| Consul leaf certificates \| Check if certificate is expiring within the threshold | ansible.builtin.set_fact | False | +| Consul leaf certificates \| Check if intermediate CA has been renewed | ansible.builtin.set_fact | False | +| Consul leaf certificates \| Renew certificate if expiring soon or intermediate CA has been renewed | block | True | +| Consul leaf certificates \| Remove old certificate before renewal | ansible.builtin.file | False | +| Consul leaf certificates \| Remove old certificate key before renewal | ansible.builtin.file | False | +| Consul leaf certificates \| Generate new consul leaf certificate | ansible.builtin.include_tasks | False | + +#### File: tasks/renew/renew_nomad.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Nomad leaf certificates \| Check if certificate exists | ansible.builtin.stat | False | +| Nomad leaf certificates \| Check if intermediate CA certificate exists | ansible.builtin.stat | False | +| Nomad leaf certificates \| Check certificate for renewal | block | True | +| Nomad leaf certificates \| Get certificate expiration date | community.crypto.x509_certificate_info | False | +| Intermediate CA \| Get intermediate CA certificate info | community.crypto.x509_certificate_info | False | +| Nomad leaf certificates \| Check if certificate is expiring within the threshold | ansible.builtin.set_fact | False | +| Nomad leaf certificates \| Check if intermediate CA has been renewed | ansible.builtin.set_fact | False | +| Nomad leaf certificates \| Renew certificate if expiring soon or intermediate CA has been renewed | block | True | +| Nomad leaf certificates \| Remove old certificate before renewal | ansible.builtin.file | False | +| Nomad leaf certificates \| Remove old certificate key before renewal | ansible.builtin.file | False | +| Nomad leaf certificates \| Generate new nomad leaf certificate | ansible.builtin.include_tasks | False | + +#### File: tasks/renew/renew_intermediate.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Intermediate CA \| Check if intermediate CA certificate exists | ansible.builtin.stat | False | +| Intermediate CA \| Check if root CA certificate exists | ansible.builtin.stat | False | +| Intermediate CA \| Check CA for renewal | block | True | +| Intermediate CA \| Get intermediate CA certificate expiration date | community.crypto.x509_certificate_info | False | +| Root CA \| Get root CA certificate info | community.crypto.x509_certificate_info | False | +| Intermediate CA \| Check if intermediate CA certificate is expiring within the threshold | ansible.builtin.set_fact | False | +| Intermediate CA \| Check if root CA has been renewed | ansible.builtin.set_fact | False | +| Intermediate CA \| Renew CA if expiring soon or root CA has been renewed | block | True | +| Intermediate CA \| Create backup directory for intermediate CA | ansible.builtin.file | False | +| Intermediate CA \| Format expiration date for backup | ansible.builtin.set_fact | False | +| Intermediate CA \| Backup existing intermediate CA certificate | ansible.builtin.command | False | +| Intermediate CA \| Backup existing intermediate CA key | ansible.builtin.command | False | +| Intermediate CA \| Generate new intermediate CA if backups were successful | ansible.builtin.include_tasks | False | +| Intermediate CA \| Generate new consul leaf certificates | ansible.builtin.include_tasks | False | +| Intermediate CA \| Generate new nomad leaf certificates | ansible.builtin.include_tasks | False | +| Intermediate CA \| Generate new vault leaf certificates | ansible.builtin.include_tasks | False | + +#### File: tasks/renew/renew_vault.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Vault leaf certificates \| Check if certificate exists | ansible.builtin.stat | False | +| Vault leaf certificates \| Check if intermediate CA certificate exists | ansible.builtin.stat | False | +| Vault leaf certificates \| Check certificate for renewal | block | True | +| Vault leaf certificates \| Get certificate expiration date | community.crypto.x509_certificate_info | False | +| Intermediate CA \| Get intermediate CA certificate info | community.crypto.x509_certificate_info | False | +| Vault leaf certificates \| Check if certificate is expiring within the threshold | ansible.builtin.set_fact | False | +| Vault leaf certificates \| Check if intermediate CA has been renewed | ansible.builtin.set_fact | False | +| Vault leaf certificates \| Renew certificate if expiring soon or intermediate CA has been renewed | block | True | +| Vault leaf certificates \| Remove old certificate before renewal | ansible.builtin.file | False | +| Vault leaf certificates \| Remove old certificate key before renewal | ansible.builtin.file | False | +| Vault leaf certificates \| Generate new vault leaf certificate | ansible.builtin.include_tasks | False | + + + + + + + + + diff --git a/roles/hashistack_ingress/.docsible b/roles/hashistack_ingress/.docsible new file mode 100644 index 0000000..7713e0f --- /dev/null +++ b/roles/hashistack_ingress/.docsible @@ -0,0 +1,13 @@ +aap_hub: null +automation_kind: null +category: null +critical: null +description: null +dt_dev: null +dt_prod: null +dt_update: 26/08/2024 +requester: null +subCategory: null +time_saving: null +users: null +version: null diff --git a/roles/hashistack_ingress/README.md b/roles/hashistack_ingress/README.md new file mode 100644 index 0000000..53897f3 --- /dev/null +++ b/roles/hashistack_ingress/README.md @@ -0,0 +1,52 @@ + + +# πŸ“ƒ Role overview + +## hashistack_ingress + + + +Description: Deploys an ingress reverse-proxy on a hashistack-ansible managed nomad cluster + + +| Field | Value | +|---------------|------------| +| Readme update | 26/08/2024 | + + + + + + + + + + + + +### Tasks + + + + + + + + +## Author Information +Bertrand Lanson + +#### License + +license (BSD, MIT) + +#### Minimum Ansible Version + +2.10 + +#### Platforms + +- **Ubuntu**: ['focal', 'jammy', 'noble'] +- **Debian**: ['bullseye', 'bookworm'] + + diff --git a/roles/hashistack_ingress/defaults/main.yml b/roles/hashistack_ingress/defaults/main.yml new file mode 100644 index 0000000..ee7df4f --- /dev/null +++ b/roles/hashistack_ingress/defaults/main.yml @@ -0,0 +1,45 @@ +--- +# defaults file for hashistack_ingress +hashistack_ingress_nomad_api_addr: "http://127.0.0.1:4646" +hashistack_ingress_nomad_api_token: + +hashistack_ingress_job_name: HashistackHAProxyIngress +hashistack_ingress_datacenters: [] +hashistack_ingress_namespace: default +hashistack_ingress_replicas: 1 +hashistack_ingress_enable_consul_service: true + +hashistack_ingress_virtual_ip_keepalived_version: latest +hashistack_ingress_virtual_ip_addr: "192.168.1.1" +hashistack_ingress_virtual_ip_interface: eth0 +hashistack_ingress_virtual_ip_vrrp_interface: "{{ hashistack_ingress_virtual_ip_interface }}" +hashistack_ingress_virtual_ip_vrrp_router_id: 50 +hashistack_ingress_virtual_ip_vrrp_priority: 100 +hashistack_ingress_virtual_ip_vrrp_advertise_interval: 1 +hashistack_ingress_virtual_ip_vrrp_password: password + +hashistack_ingress_enable_http: true +hashistack_ingress_enable_https: false +hashistack_ingress_enable_prometheus_metrics: false +hashistack_ingress_enable_admin_interface: false +hashistack_ingress_admin_interface_password: password + +hashistack_ingress_virtual_ip_haproxy_version: latest +hashistack_ingress_haproxy_global: + - log /dev/log local0 + - log /dev/log local1 notice + - stats socket {{ deploy_haproxy_socket }} level admin + - chroot {{ deploy_haproxy_chroot }} + - daemon + - description hashistack haproxy +hashistack_ingress_haproxy_defaults: + - log global + - mode http + - option httplog + - option dontlognull + - timeout connect 5000 + - timeout client 5000 + - timeout server 5000 +hashistack_ingress_haproxy_frontends: [] +hashistack_ingress_haproxy_backends: [] +hashistack_ingress_haproxy_listen: [] diff --git a/roles/hashistack_ingress/handlers/main.yml b/roles/hashistack_ingress/handlers/main.yml new file mode 100644 index 0000000..81ae4df --- /dev/null +++ b/roles/hashistack_ingress/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for hashistack_ingress diff --git a/roles/hashistack_ingress/meta/main.yml b/roles/hashistack_ingress/meta/main.yml new file mode 100644 index 0000000..01ba49c --- /dev/null +++ b/roles/hashistack_ingress/meta/main.yml @@ -0,0 +1,28 @@ +--- +# meta file for hashistack_ingress +galaxy_info: + namespace: "ednz_cloud" + role_name: "hashistack_ingress" + author: "Bertrand Lanson" + description: "Deploys an ingress reverse-proxy on a hashistack-ansible managed nomad cluster" + license: "license (BSD, MIT)" + min_ansible_version: "2.10" + platforms: + - name: Ubuntu + versions: + - focal + - jammy + - noble + - name: Debian + versions: + - bullseye + - bookworm + galaxy_tags: + - "ubuntu" + - "debian" + - "hashicorp" + - "nomad" + - "haproxy" + - "ingress" + +dependencies: [] diff --git a/roles/hashistack_ingress/tasks/main.yml b/roles/hashistack_ingress/tasks/main.yml new file mode 100644 index 0000000..da865fa --- /dev/null +++ b/roles/hashistack_ingress/tasks/main.yml @@ -0,0 +1,2 @@ +--- +# task/main file for hashistack_ingress diff --git a/roles/hashistack_ingress/templates/chk_haproxy.sh.j2 b/roles/hashistack_ingress/templates/chk_haproxy.sh.j2 new file mode 100644 index 0000000..50d4884 --- /dev/null +++ b/roles/hashistack_ingress/templates/chk_haproxy.sh.j2 @@ -0,0 +1 @@ +#! /bin/sh diff --git a/roles/hashistack_ingress/templates/haproxy.cfg.j2 b/roles/hashistack_ingress/templates/haproxy.cfg.j2 new file mode 100644 index 0000000..bf43a0d --- /dev/null +++ b/roles/hashistack_ingress/templates/haproxy.cfg.j2 @@ -0,0 +1,31 @@ +# {{ ansible_managed }} +global +{% for option in hashistack_ingress_haproxy_global %} + {{ option }} +{% endfor %} + +defaults +{% for option in hashistack_ingress_haproxy_defaults %} + {{ option }} +{% endfor %} + +{% for frontend in hashistack_ingress_haproxy_frontends + hashistack_ingress_mandatory_frontends %} +frontend {{ frontend.name }} +{% for option in frontend.options %} + {{ option }} +{% endfor %} +{% endfor %} + +{% for backend in hashistack_ingress_haproxy_backends %} +backend {{ backend.name }} +{% for option in backend.options%} + {{ option }} +{% endfor %} +{% endfor %} + +{% for listen in hashistack_ingress_haproxy_listen %} +listen {{ listen.name }} +{% for option in listen.options %} + {{ option }} +{% endfor %} +{% endfor %} diff --git a/roles/hashistack_ingress/templates/ingress.job.hcl.j2 b/roles/hashistack_ingress/templates/ingress.job.hcl.j2 new file mode 100644 index 0000000..188e915 --- /dev/null +++ b/roles/hashistack_ingress/templates/ingress.job.hcl.j2 @@ -0,0 +1,155 @@ +job "{{ hashistack_ingress_job_name }}" { + datacenters = {{ hashistack_ingress_datacenters }} + type = "service" + priority = 85 + namespace = {{ hashistack_ingress_namespace }} + + group "haproxy" { + network { + mode = "bridge" + port "http" { + to = 80 + static = 80 + } + port "https" { + to = 443 + static = 443 + } + port "stats" { + to = 9000 + } + } + +{% if hashistack_ingress_enable_http %} + service { + name = "haproxy-http" + provider = "{{ "consul" if hashistack_ingress_enable_consul_service else "nomad"}}" + port = "http" + task = "loadbalancer" + check { + type = "http" + port = "stats" + path = "/health" + interval = "10s" + timeout = "2s" + } + tags = [] + } +{% endif %} + +{% if hashistack_ingress_enable_https %} + service { + name = "haproxy-https" + provider = "{{ "consul" if hashistack_ingress_enable_consul_service else "nomad"}}" + port = "https" + task = "loadbalancer" + check { + type = "http" + port = "stats" + path = "/health" + interval = "10s" + timeout = "2s" + } + tags = [] + } +{% endif %} + + service { + name = "haproxy-stats" + provider = "{{ "consul" if hashistack_ingress_enable_consul_service else "nomad"}}" + port = "stats" + task = "loadbalancer" + check { + type = "http" + port = "stats" + path = "/health" + interval = "10s" + timeout = "2s" + } + tags = [] + } + + + +{% if hashistack_ingress_enable_prometheus_metrics %} + service { + name = "loadbalancer-exporter" + port = "prometheus-exporter" + task = "loadbalancer" + tags = [] + } +{% endif %} + + task "keepalived" { + driver = "docker" + lifecycle { + hook = "poststart" + sidecar = true + } + config { + image = "{{ hashistack_ingress_keepalived_image }}:{{ hashistack_ingress_virtual_ip_keepalived_version }}" + network_mode = "host" + cap_add = [ + "NET_ADMIN", + "NET_BROADCAST", + "NET_RAW" + ] + mount { + type = "bind" + source = "secrets/keepalived.conf" + target = "/etc/keepalived/keepalived.conf" + } + mount { + type = "bind" + source = "secrets/chk_haproxy.sh" + target = "/etc/keepalived/scripts.d/chk_haproxy.sh" + } + mount { + type = "bind" + target = "/var/run/docker.sock" + source = "/var/run/docker.sock" + readonly = true + } + } + template { + data = <<-EOT +{% include "keepalived.conf.j2" %} +EOT + destination = "secrets/keepalived.conf" + } + template { + data = <<-EOT +{% include "chk_haproxy.sh.j2" %} +EOT + destination = "secrets/chk_haproxy.sh" + perms = "755" + } + resources { + cpu = 50 + memory = 10 + } + } + + task "loadbalancer" { + driver = "docker" + config { + image = "{{ hashistack_ingress_haproxy_image }}:{{ hashistack_ingress_virtual_ip_haproxy_version }}" + mount { + type = "bind" + source = "secrets/haproxy.cfg" + target = "/usr/local/etc/haproxy/haproxy.cfg" + } + } + template { + data = <<-EOT +{% include "haproxy.cfg.j2" %} +EOT + destination = "secrets/haproxy.cfg" + } + resources { + cpu = 128 + memory = 256 + } + } + } +} diff --git a/roles/hashistack_ingress/templates/keepalived.conf.j2 b/roles/hashistack_ingress/templates/keepalived.conf.j2 new file mode 100644 index 0000000..7a6a2f3 --- /dev/null +++ b/roles/hashistack_ingress/templates/keepalived.conf.j2 @@ -0,0 +1,37 @@ +global_defs { + script_user root + enable_script_security +} + +vrrp_script chk_haproxy { + script "/etc/keepalived/scripts.d/chk_haproxy.sh" + user root + interval 3 + weight 0 + rise 6 + fall 1 +} + +vrrp_instance haproxy { + interface {{ hashistack_ingress_virtual_ip_vrrp_interface }} + + state {{ hashistack_ingress_keepalived_init_state }} + virtual_router_id {{ hashistack_ingress_virtual_ip_vrrp_router_id }} + priority {{ hashistack_ingress_virtual_ip_vrrp_priority }} + advert_int {{ hashistack_ingress_virtual_ip_vrrp_advertise_interval }} + + authentication { + auth_type PASS + auth_pass {{ hashistack_ingress_virtual_ip_vrrp_password }} + } + + virtual_ipaddress { + {{ hashistack_ingress_virtual_ip_addr }}/32 dev {{ hashistack_ingress_virtual_ip_interface }} + } + + track_script { + chk_haproxy + } + + notify /etc/keepalived/scripts.d/notify.sh +} diff --git a/roles/hashistack_ingress/vars/main.yml b/roles/hashistack_ingress/vars/main.yml new file mode 100644 index 0000000..6426983 --- /dev/null +++ b/roles/hashistack_ingress/vars/main.yml @@ -0,0 +1,28 @@ +--- +# vars file for hashistack_ingress +hashistack_ingress_keepalived_image: ednxzu/keepalived +hashistack_ingress_haproxy_image: haproxytech/haproxy-debian + +hashistack_ingress_keepalived_init_state: BACKUP + +hashistack_ingress_template_haproxy_cfg: "{{ lookup('ansible.builtin.template', 'haproxy.cfg.j2') }}" +hashistack_ingress_template_keepalived_conf: "{{ lookup('ansible.builtin.template', 'keepalived.conf.j2') }}" +hashistack_ingress_template_chk_haproxy_sh: "{{ lookup('ansible.builtin.template', 'chk_haproxy.sh.j2') }}" + +hashistack_ingress_mandatory_frontends: + - name: monitoring + options: + - bind :9000 + - mode http + - option httpchk + - "{{'stats enable' if hashistack_ingress_enable_admin_interface else omit }}" + - "{{'stats uri /stats' if hashistack_ingress_enable_admin_interface else omit }}" + - "{{'stats refresh 30s' if hashistack_ingress_enable_admin_interface else omit }}" + - "{{'stats show-desc' if hashistack_ingress_enable_admin_interface else omit }}" + - "{{'stats show-legends' if hashistack_ingress_enable_admin_interface else omit }}" + - "{{'stats auth admin:'~hashistack_ingress_admin_interface_password if hashistack_ingress_enable_admin_interface else omit }}" + - http-check send meth GET uri /health ver HTTP/1.1 hdr Host localhost + - http-check expect status 200 + - acl health_check_ok nbsrv() ge 1 + - monitor-uri /health + - "{{'http-request use-service prometheus-exporter if { path /metrics }' if hashistack_ingress_enable_prometheus_metrics else omit }}" diff --git a/roles/nomad/.docsible b/roles/nomad/.docsible new file mode 100644 index 0000000..7713e0f --- /dev/null +++ b/roles/nomad/.docsible @@ -0,0 +1,13 @@ +aap_hub: null +automation_kind: null +category: null +critical: null +description: null +dt_dev: null +dt_prod: null +dt_update: 26/08/2024 +requester: null +subCategory: null +time_saving: null +users: null +version: null diff --git a/roles/nomad/README.md b/roles/nomad/README.md new file mode 100644 index 0000000..f05bde8 --- /dev/null +++ b/roles/nomad/README.md @@ -0,0 +1,221 @@ + + +# πŸ“ƒ Role overview + +## nomad + + + +Description: Install and configure hashicorp nomad for debian-based distros. + + +| Field | Value | +|--------------------- |-----------------| +| Readme update | 26/08/2024 | + + + + + + +### Defaults + +**These are static variables with lower priority** + +#### File: defaults/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [nomad_version](defaults/main.yml#L4) | str | `latest` | n/a | n/a | +| [nomad_start_service](defaults/main.yml#L5) | bool | `True` | n/a | n/a | +| [nomad_config_dir](defaults/main.yml#L6) | str | `/etc/nomad.d` | n/a | n/a | +| [nomad_data_dir](defaults/main.yml#L7) | str | `/opt/nomad` | n/a | n/a | +| [nomad_certs_dir](defaults/main.yml#L8) | str | `{{ nomad_config_dir }}/tls` | n/a | n/a | +| [nomad_logs_dir](defaults/main.yml#L9) | str | `/var/log/nomad` | n/a | n/a | +| [nomad_extra_files](defaults/main.yml#L11) | bool | `False` | n/a | n/a | +| [nomad_extra_files_list](defaults/main.yml#L12) | list | `[]` | n/a | n/a | +| [nomad_env_variables](defaults/main.yml#L14) | dict | `{}` | n/a | n/a | +| [nomad_extra_configuration](defaults/main.yml#L25) | dict | `{}` | n/a | n/a | +| [nomad_region](defaults/main.yml#L31) | str | `global` | n/a | n/a | +| [nomad_datacenter](defaults/main.yml#L32) | str | `dc1` | n/a | n/a | +| [nomad_bind_addr](defaults/main.yml#L38) | str | `0.0.0.0` | n/a | n/a | +| [nomad_advertise_addr](defaults/main.yml#L39) | str | `{{ ansible_default_ipv4.address }}` | n/a | n/a | +| [nomad_address_configuration](defaults/main.yml#L40) | dict | `{'bind_addr': '{{ nomad_bind_addr }}', 'addresses': {'http': '{{ nomad_advertise_addr }}', 'rpc': '{{ nomad_advertise_addr }}', 'serf': '{{ nomad_advertise_addr }}'}, 'advertise': {'http': '{{ nomad_advertise_addr }}', 'rpc': '{{ nomad_advertise_addr }}', 'serf': '{{ nomad_advertise_addr }}'}, 'ports': {'http': 4646, 'rpc': 4647, 'serf': 4648}}` | n/a | n/a | +| [nomad_autopilot_configuration](defaults/main.yml#L59) | dict | `{}` | n/a | n/a | +| [nomad_leave_on_interrupt](defaults/main.yml#L65) | bool | `False` | n/a | n/a | +| [nomad_leave_on_terminate](defaults/main.yml#L66) | bool | `False` | n/a | n/a | +| [nomad_enable_server](defaults/main.yml#L72) | bool | `True` | n/a | n/a | +| [nomad_server_bootstrap_expect](defaults/main.yml#L73) | int | `1` | n/a | n/a | +| [nomad_server_configuration](defaults/main.yml#L74) | dict | `{'enabled': '{{ nomad_enable_server }}', 'data_dir': '{{ nomad_data_dir }}/server', 'encrypt': "{{ 'mysupersecretgossipencryptionkey'\|b64encode }}", 'server_join': {'retry_join': ['{{ ansible_default_ipv4.address }}']}}` | n/a | n/a | +| [nomad_enable_client](defaults/main.yml#L86) | bool | `False` | n/a | n/a | +| [nomad_client_configuration](defaults/main.yml#L87) | dict | `{'enabled': '{{ nomad_enable_client }}', 'state_dir': '{{ nomad_data_dir }}/client', 'cni_path': '/opt/cni/bin', 'bridge_network_name': 'nomad', 'bridge_network_subnet': '172.26.64.0/20'}` | n/a | n/a | +| [nomad_ui_configuration](defaults/main.yml#L98) | dict | `{'enabled': '{{ nomad_enable_server }}'}` | n/a | n/a | +| [nomad_driver_enable_docker](defaults/main.yml#L105) | bool | `True` | n/a | n/a | +| [nomad_driver_enable_podman](defaults/main.yml#L106) | bool | `False` | n/a | n/a | +| [nomad_driver_enable_raw_exec](defaults/main.yml#L107) | bool | `False` | n/a | n/a | +| [nomad_driver_enable_java](defaults/main.yml#L108) | bool | `False` | n/a | n/a | +| [nomad_driver_enable_qemu](defaults/main.yml#L109) | bool | `False` | n/a | n/a | +| [nomad_driver_configuration](defaults/main.yml#L111) | dict | `{'raw_exec': {'enabled': False}}` | n/a | n/a | +| [nomad_driver_extra_configuration](defaults/main.yml#L115) | dict | `{}` | n/a | n/a | +| [nomad_log_level](defaults/main.yml#L121) | str | `info` | n/a | n/a | +| [nomad_enable_log_to_file](defaults/main.yml#L122) | bool | `False` | n/a | n/a | +| [nomad_log_to_file_configuration](defaults/main.yml#L123) | dict | `{'log_file': '{{ nomad_logs_dir }}/nomad.log', 'log_rotate_duration': '24h', 'log_rotate_max_files': 30}` | n/a | n/a | +| [nomad_acl_configuration](defaults/main.yml#L132) | dict | `{'enabled': False, 'token_ttl': '30s', 'policy_ttl': '60s', 'role_ttl': '60s'}` | n/a | n/a | +| [nomad_enable_tls](defaults/main.yml#L142) | bool | `False` | n/a | n/a | +| [nomad_tls_configuration](defaults/main.yml#L143) | dict | `{'http': True, 'rpc': True, 'ca_file': '/etc/ssl/certs/ca-certificates.crt', 'cert_file': '{{ nomad_certs_dir }}/cert.pem', 'key_file': '{{ nomad_certs_dir }}/key.pem', 'verify_server_hostname': True}` | n/a | n/a | +| [nomad_certificates_extra_files_dir](defaults/main.yml#L151) | list | `[]` | n/a | n/a | +| [nomad_telemetry_configuration](defaults/main.yml#L160) | dict | `{'collection_interval': '10s', 'disable_hostname': False, 'use_node_name': False, 'publish_allocation_metrics': False, 'publish_node_metrics': False, 'prefix_filter': [], 'disable_dispatched_job_summary_metrics': False, 'prometheus_metrics': False}` | n/a | n/a | +| [nomad_enable_consul_integration](defaults/main.yml#L174) | bool | `False` | n/a | n/a | +| [nomad_consul_integration_configuration](defaults/main.yml#L175) | dict | `{'address': '127.0.0.1:8500', 'auto_advertise': True, 'ssl': False, 'token': '', 'tags': []}` | n/a | n/a | +| [nomad_consul_integration_tls_configuration](defaults/main.yml#L182) | dict | `{'ca_file': '/etc/ssl/certs/ca-certificates.crt'}` | n/a | n/a | +| [nomad_consul_integration_server_configuration](defaults/main.yml#L185) | dict | `{'server_auto_join': True}` | n/a | n/a | +| [nomad_consul_integration_client_configuration](defaults/main.yml#L188) | dict | `{'client_auto_join': True, 'grpc_address': '127.0.0.1:8502'}` | n/a | n/a | +| [nomad_consul_integration_client_tls_configuration](defaults/main.yml#L192) | dict | `{'grpc_ca_file': '/etc/ssl/certs/ca-certificates.crt'}` | n/a | n/a | +| [nomad_enable_vault_integration](defaults/main.yml#L199) | bool | `False` | n/a | n/a | +| [nomad_vault_integration_configuration](defaults/main.yml#L200) | dict | `{}` | n/a | n/a | + + +### Vars + +**These are variables with higher priority** +#### File: vars/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [nomad_user](vars/main.yml#L3) | str | `nomad` | n/a | n/a | +| [nomad_group](vars/main.yml#L4) | str | `nomad` | n/a | n/a | +| [nomad_binary_path](vars/main.yml#L5) | str | `/usr/local/bin/nomad` | n/a | n/a | +| [nomad_deb_architecture_map](vars/main.yml#L6) | dict | `{'x86_64': 'amd64', 'aarch64': 'arm64', 'armv7l': 'arm', 'armv6l': 'arm'}` | n/a | n/a | +| [nomad_architecture](vars/main.yml#L11) | str | `{{ nomad_deb_architecture_map[ansible_architecture] \| default(ansible_architecture) }}` | n/a | n/a | +| [nomad_service_name](vars/main.yml#L12) | str | `nomad` | n/a | n/a | +| [nomad_github_api](vars/main.yml#L13) | str | `https://api.github.com/repos` | n/a | n/a | +| [nomad_github_project](vars/main.yml#L14) | str | `hashicorp/nomad` | n/a | n/a | +| [nomad_github_url](vars/main.yml#L15) | str | `https://github.com` | n/a | n/a | +| [nomad_repository_url](vars/main.yml#L16) | str | `https://releases.hashicorp.com/nomad` | n/a | n/a | +| [nomad_configuration](vars/main.yml#L18) | dict | `{'datacenter': '{{ nomad_datacenter }}', 'region': '{{ nomad_region }}', 'data_dir': '{{ nomad_data_dir }}', 'leave_on_interrupt': '{{ nomad_leave_on_interrupt }}', 'leave_on_terminate': '{{ nomad_leave_on_terminate }}', 'acl': '{{ nomad_acl_configuration }}', 'server': '{{ nomad_server_configuration }}', 'client': '{{ nomad_client_configuration }}', 'ui': '{{ nomad_ui_configuration }}', 'log_level': '{{ nomad_log_level }}'}` | n/a | n/a | +| [nomad_configuration_string](vars/main.yml#L30) | str | `` | n/a | n/a | + + +### Tasks + + +#### File: tasks/recursive_copy_extra_dirs.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Nomad \| Ensure destination directory exists | ansible.builtin.file | False | +| Nomad \| Create extra directory sources | ansible.builtin.file | True | +| Nomad \| Template extra directory sources | ansible.builtin.template | True | + +#### File: tasks/merge_variables.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Nomad \| Merge stringified configuration | vars | False | +| Nomad \| Merge addresses configuration | vars | False | +| Nomad \| Merge consul integration configuration | block | True | +| Nomad \| Merge consul tls configuration | block | True | +| Nomad \| Merge consul default client configuration | vars | False | +| Nomad \| Merge consul configuration for nomad servers | block | True | +| Nomad \| Merge consul default server configuration | vars | False | +| Nomad \| Merge consul configuration for nomad clients | block | True | +| Nomad \| Merge consul default client configuration | vars | False | +| Nomad \| Merge consul tls client configuration | vars | True | +| Nomad \| Merge consul block into main configuration | vars | False | +| Nomad \| Merge TLS configuration | block | True | +| Nomad \| Merge TLS configuration | vars | False | +| Nomad \| Add certificates directory to extra_files_dir | ansible.builtin.set_fact | False | +| Nomad \| Merge plugin configuration | vars | True | +| Nomad \| Merge extra configuration settings | vars | False | +| Nomad \| Merge log to file configuration | vars | True | +| Nomad \| Merge telemetry configuration | vars | False | + +#### File: tasks/main.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Nomad \| Set reload-check & restart-check variable | ansible.builtin.set_fact | False | +| Nomad \| Import merge_variables.yml | ansible.builtin.include_tasks | False | +| Nomad \| Import prerequisites.yml | ansible.builtin.include_tasks | False | +| Nomad \| Import install.yml | ansible.builtin.include_tasks | False | +| Nomad \| Import configure.yml | ansible.builtin.include_tasks | False | +| Nomad \| Populate service facts | ansible.builtin.service_facts | False | +| Nomad \| Set restart-check variable | ansible.builtin.set_fact | True | +| Nomad \| Enable service: {{ nomad_service_name }} | ansible.builtin.service | False | +| Nomad \| Reload systemd daemon | ansible.builtin.systemd | True | +| Nomad \| Start service: {{ nomad_service_name }} | ansible.builtin.service | True | + +#### File: tasks/install.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Nomad \| Get latest release of nomad | block | True | +| Nomad \| Get latest nomad release from github api | ansible.builtin.uri | False | +| Nomad \| Set wanted nomad version to latest tag | ansible.builtin.set_fact | False | +| Nomad \| Set wanted nomad version to {{ nomad_version }} | ansible.builtin.set_fact | True | +| Nomad \| Get current nomad version | block | False | +| Nomad \| Stat nomad version file | ansible.builtin.stat | False | +| Nomad \| Get current nomad version | ansible.builtin.slurp | True | +| Nomad \| Download and install nomad binary | block | True | +| Nomad \| Set nomad package name to download | ansible.builtin.set_fact | False | +| Nomad \| Download checksum file for nomad archive | ansible.builtin.get_url | False | +| Nomad \| Extract correct checksum from checksum file | ansible.builtin.command | False | +| Nomad \| Parse the expected checksum | ansible.builtin.set_fact | False | +| Nomad \| Download nomad binary archive | ansible.builtin.get_url | False | +| Nomad \| Create temporary directory for archive decompression | ansible.builtin.file | False | +| Nomad \| Unpack nomad archive | ansible.builtin.unarchive | False | +| Nomad \| Copy nomad binary to {{ nomad_binary_path }} | ansible.builtin.copy | False | +| Nomad \| Update nomad version file | ansible.builtin.copy | False | +| Nomad \| Set restart-check variable | ansible.builtin.set_fact | False | +| Nomad \| Cleanup temporary directory | ansible.builtin.file | False | +| Nomad \| Copy systemd service file for nomad | ansible.builtin.template | False | +| Nomad \| Set reload-check & restart-check variable | ansible.builtin.set_fact | True | + +#### File: tasks/prerequisites.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Nomad \| Create group {{ nomad_group }} | ansible.builtin.group | False | +| Nomad \| Create user {{ nomad_user }} | ansible.builtin.user | False | +| Nomad \| Create directory {{ nomad_config_dir }} | ansible.builtin.file | False | +| Nomad \| Create directory {{ nomad_data_dir }} | ansible.builtin.file | False | +| Nomad \| Create directory {{ nomad_certs_dir }} | ansible.builtin.file | False | +| Nomad \| Create directory {{ nomad_logs_dir }} | ansible.builtin.file | True | + +#### File: tasks/configure.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Nomad \| Create nomad.env | ansible.builtin.template | False | +| Nomad \| Copy nomad.json template | ansible.builtin.template | False | +| Nomad \| Set restart-check variable | ansible.builtin.set_fact | True | +| Nomad \| Copy extra configuration files | block | True | +| Nomad \| Get extra file types | ansible.builtin.stat | False | +| Nomad \| Set list for file sources | vars | True | +| Nomad \| Set list for directory sources | vars | True | +| Nomad \| Template extra file sources | ansible.builtin.template | True | +| Nomad \| Template extra directory sources | ansible.builtin.include_tasks | True | + + + + + + + +## Author Information +Bertrand Lanson + +#### License + +license (BSD, MIT) + +#### Minimum Ansible Version + +2.10 + +#### Platforms + +- **Ubuntu**: ['focal', 'jammy', 'noble'] +- **Debian**: ['bullseye', 'bookworm'] + + diff --git a/roles/vault/.docsible b/roles/vault/.docsible new file mode 100644 index 0000000..7713e0f --- /dev/null +++ b/roles/vault/.docsible @@ -0,0 +1,13 @@ +aap_hub: null +automation_kind: null +category: null +critical: null +description: null +dt_dev: null +dt_prod: null +dt_update: 26/08/2024 +requester: null +subCategory: null +time_saving: null +users: null +version: null diff --git a/roles/vault/README.md b/roles/vault/README.md new file mode 100644 index 0000000..e26d2a1 --- /dev/null +++ b/roles/vault/README.md @@ -0,0 +1,193 @@ + + +# πŸ“ƒ Role overview + +## vault + + + +Description: Install and configure hashicorp vault for debian-based distros. + + +| Field | Value | +|--------------------- |-----------------| +| Readme update | 26/08/2024 | + + + + + + +### Defaults + +**These are static variables with lower priority** + +#### File: defaults/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [vault_version](defaults/main.yml#L3) | str | `latest` | n/a | n/a | +| [vault_start_service](defaults/main.yml#L4) | bool | `True` | n/a | n/a | +| [vault_config_dir](defaults/main.yml#L5) | str | `/etc/vault.d` | n/a | n/a | +| [vault_data_dir](defaults/main.yml#L6) | str | `/opt/vault` | n/a | n/a | +| [vault_certs_dir](defaults/main.yml#L7) | str | `{{ vault_config_dir }}/tls` | n/a | n/a | +| [vault_logs_dir](defaults/main.yml#L8) | str | `/var/log/vault` | n/a | n/a | +| [vault_extra_files](defaults/main.yml#L10) | bool | `False` | n/a | n/a | +| [vault_extra_files_list](defaults/main.yml#L11) | list | `[]` | n/a | n/a | +| [vault_env_variables](defaults/main.yml#L13) | dict | `{}` | n/a | n/a | +| [vault_extra_configuration](defaults/main.yml#L24) | dict | `{}` | n/a | n/a | +| [vault_cluster_name](defaults/main.yml#L30) | str | `vault` | n/a | n/a | +| [vault_bind_addr](defaults/main.yml#L31) | str | `0.0.0.0` | n/a | n/a | +| [vault_cluster_addr](defaults/main.yml#L32) | str | `{{ ansible_default_ipv4.address }}` | n/a | n/a | +| [vault_enable_ui](defaults/main.yml#L33) | bool | `True` | n/a | n/a | +| [vault_disable_mlock](defaults/main.yml#L34) | bool | `False` | n/a | n/a | +| [vault_disable_cache](defaults/main.yml#L35) | bool | `False` | n/a | n/a | +| [vault_storage_configuration](defaults/main.yml#L41) | dict | `{'file': {'path': '{{ vault_data_dir }}'}}` | n/a | n/a | +| [vault_enable_tls](defaults/main.yml#L49) | bool | `False` | n/a | n/a | +| [vault_listener_configuration](defaults/main.yml#L50) | list | `[{'tcp': {'address': '{{ vault_cluster_addr }}:8200', 'tls_disable': True}}]` | n/a | n/a | +| [vault_tls_listener_configuration](defaults/main.yml#L55) | list | `[{'tcp': {'tls_disable': False, 'tls_cert_file': '{{ vault_certs_dir }}/cert.pem', 'tls_key_file': '{{ vault_certs_dir }}/key.pem', 'tls_disable_client_certs': True}}]` | n/a | n/a | +| [vault_certificates_extra_files_dir](defaults/main.yml#L62) | list | `[]` | n/a | n/a | +| [vault_extra_listener_configuration](defaults/main.yml#L67) | list | `[]` | n/a | n/a | +| [vault_enable_service_registration](defaults/main.yml#L73) | bool | `False` | n/a | n/a | +| [vault_service_registration_configuration](defaults/main.yml#L74) | dict | `{'consul': {'address': '127.0.0.1:8500', 'scheme': 'http', 'token': ''}}` | n/a | n/a | +| [vault_enable_plugins](defaults/main.yml#L84) | bool | `False` | n/a | n/a | +| [vault_plugins_directory](defaults/main.yml#L85) | str | `{{ vault_config_dir }}/plugins` | n/a | n/a | +| [vault_log_level](defaults/main.yml#L91) | str | `info` | n/a | n/a | +| [vault_enable_log_to_file](defaults/main.yml#L92) | bool | `False` | n/a | n/a | +| [vault_log_to_file_configuration](defaults/main.yml#L93) | dict | `{'log_file': '{{ vault_logs_dir }}/vault.log', 'log_rotate_duration': '24h', 'log_rotate_max_files': 30}` | n/a | n/a | + + +### Vars + +**These are variables with higher priority** +#### File: vars/main.yml + +| Var | Type | Value |Required | Title | +|--------------|--------------|-------------|-------------|-------------| +| [vault_user](vars/main.yml#L3) | str | `vault` | n/a | n/a | +| [vault_group](vars/main.yml#L4) | str | `vault` | n/a | n/a | +| [vault_binary_path](vars/main.yml#L5) | str | `/usr/local/bin/vault` | n/a | n/a | +| [vault_deb_architecture_map](vars/main.yml#L6) | dict | `{'x86_64': 'amd64', 'aarch64': 'arm64', 'armv7l': 'arm', 'armv6l': 'arm'}` | n/a | n/a | +| [vault_architecture](vars/main.yml#L11) | str | `{{ vault_deb_architecture_map[ansible_architecture] \| default(ansible_architecture) }}` | n/a | n/a | +| [vault_service_name](vars/main.yml#L12) | str | `vault` | n/a | n/a | +| [vault_github_api](vars/main.yml#L13) | str | `https://api.github.com/repos` | n/a | n/a | +| [vault_github_project](vars/main.yml#L14) | str | `hashicorp/vault` | n/a | n/a | +| [vault_github_url](vars/main.yml#L15) | str | `https://github.com` | n/a | n/a | +| [vault_repository_url](vars/main.yml#L16) | str | `https://releases.hashicorp.com/vault` | n/a | n/a | +| [vault_configuration](vars/main.yml#L18) | dict | `{'cluster_name': '{{ vault_cluster_name }}', 'cluster_addr': "{{ 'https' if vault_enable_tls else 'http'}}://{{ vault_cluster_addr }}:8201", 'api_addr': "{{ 'https' if vault_enable_tls else 'http'}}://{{ vault_cluster_addr }}:8200", 'ui': '{{ vault_enable_ui }}', 'disable_mlock': '{{ vault_disable_mlock }}', 'disable_cache': '{{ vault_disable_cache }}', 'listener': '{{ vault_listener_configuration }}', 'storage': '{{ vault_storage_configuration }}'}` | n/a | n/a | + + +### Tasks + + +#### File: tasks/recursive_copy_extra_dirs.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Vault \| Ensure destination directory exists | ansible.builtin.file | False | +| Vault \| Create extra directory sources | ansible.builtin.file | True | +| Vault \| Template extra directory sources | ansible.builtin.template | True | + +#### File: tasks/merge_variables.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Vault \| Merge listener configuration | block | False | +| Vault \| Merge tls listener configuration | vars | True | +| Vault \| Merge extra listener configuration | vars | False | +| Vault \| Add certificates directory to extra_files_dir | ansible.builtin.set_fact | False | +| Vault \| Merge service registration configuration | vars | True | +| Vault \| Merge plugins configuration | vars | True | +| Vault \| Merge logging configuration | vars | True | +| Vault \| Merge extra configuration settings | vars | True | + +#### File: tasks/main.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Vault \| Set reload-check & restart-check variable | ansible.builtin.set_fact | False | +| Vault \| Import merge_variables.yml | ansible.builtin.include_tasks | False | +| Vault \| Import prerequisites.yml | ansible.builtin.include_tasks | False | +| Vault \| Import install.yml | ansible.builtin.include_tasks | False | +| Vault \| Import configure.yml | ansible.builtin.include_tasks | False | +| Vault \| Populate service facts | ansible.builtin.service_facts | False | +| Vault \| Set restart-check variable | ansible.builtin.set_fact | True | +| Vault \| Enable service: {{ vault_service_name }} | ansible.builtin.service | False | +| Vault \| Reload systemd daemon | ansible.builtin.systemd | True | +| Vault \| Start service: {{ vault_service_name }} | ansible.builtin.service | True | + +#### File: tasks/install.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Vault \| Get latest release of vault | block | True | +| Vault \| Get latest vault release from github api | ansible.builtin.uri | False | +| Vault \| Set wanted vault version to latest tag | ansible.builtin.set_fact | False | +| Vault \| Set wanted vault version to {{ vault_version }} | ansible.builtin.set_fact | True | +| Vault \| Get current vault version | block | False | +| Vault \| Stat vault version file | ansible.builtin.stat | False | +| Vault \| Get current vault version | ansible.builtin.slurp | True | +| Vault \| Download and install vault binary | block | True | +| Vault \| Set vault package name to download | ansible.builtin.set_fact | False | +| Vault \| Download checksum file for vault archive | ansible.builtin.get_url | False | +| Vault \| Extract correct checksum from checksum file | ansible.builtin.command | False | +| Vault \| Parse the expected checksum | ansible.builtin.set_fact | False | +| Vault \| Download vault binary archive | ansible.builtin.get_url | False | +| Vault \| Create temporary directory for archive decompression | ansible.builtin.file | False | +| Vault \| Unpack vault archive | ansible.builtin.unarchive | False | +| Vault \| Copy vault binary to {{ vault_binary_path }} | ansible.builtin.copy | False | +| Vault \| Update vault version file | ansible.builtin.copy | False | +| Vault \| Set restart-check variable | ansible.builtin.set_fact | False | +| Vault \| Cleanup temporary directory | ansible.builtin.file | False | +| Vault \| Copy systemd service file for vault | ansible.builtin.template | False | +| Vault \| Set reload-check & restart-check variable | ansible.builtin.set_fact | True | +| Vault \| Copy systemd service file for vault | ansible.builtin.template | False | + +#### File: tasks/prerequisites.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Vault \| Create group {{ vault_group }} | ansible.builtin.group | False | +| Vault \| Create user {{ vault_user }} | ansible.builtin.user | False | +| Vault \| Create directory {{ vault_config_dir }} | ansible.builtin.file | False | +| Vault \| Create directory {{ vault_data_dir}} | ansible.builtin.file | False | +| Vault \| Create directory {{ vault_certs_dir }} | ansible.builtin.file | False | +| Vault \| Create directory {{ vault_logs_dir }} | ansible.builtin.file | True | + +#### File: tasks/configure.yml + +| Name | Module | Has Conditions | +| ---- | ------ | --------- | +| Vault \| Create vault.env | ansible.builtin.template | False | +| Vault \| Copy vault.json template | ansible.builtin.template | False | +| Vault \| Set restart-check variable | ansible.builtin.set_fact | True | +| Vault \| Copy extra configuration files | block | True | +| Vault \| Get extra file types | ansible.builtin.stat | False | +| Vault \| Set list for file sources | vars | True | +| Vault \| Set list for directory sources | vars | True | +| Vault \| Template extra file sources | ansible.builtin.template | True | +| Vault \| Template extra directory sources | ansible.builtin.include_tasks | True | + + + + + + + +## Author Information +Bertrand Lanson + +#### License + +license (BSD, MIT) + +#### Minimum Ansible Version + +2.10 + +#### Platforms + +- **Ubuntu**: ['focal', 'jammy', 'noble'] +- **Debian**: ['bullseye', 'bookworm'] + +