diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..756f1c7
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,357 @@
+
+# Consul Ansible Role
+
+
+
+
+## Table of Contents
+
+1. [Overview](#1-overview)
+2. [Supported Operating Systems](#2-supported-operating-systems)
+3. [Prerequisites & Known Limitations](#3-prerequisites--known-limitations)
+4. [Architecture & Core Components](#4-architecture--core-components)
+5. [Configuration Overview](#5-configuration-overview)
+6. [Installation Flow](#6-installation-flow)
+7. [Running Consul](#7-running-consul)
+8. [Validation & Testing](#8-validation--testing)
+9. [Best Practices Followed](#9-best-practices-followed)
+10. [Troubleshooting](#10-troubleshooting)
+11. [Conclusion](#11-conclusion)
+12. [References](#12-references)
+13. [Author](#13-author)
+
+## 1. Overview
+
+**HashiCorp Consul** is a service networking platform that enables:
+
+- Service Discovery
+- Service Mesh
+- Health Checking
+- Key-Value Storage
+- Secure Service-to-Service Communication
+
+It is widely used in distributed systems and microservices architectures to provide dynamic infrastructure management.
+
+### Problems Consul Solves
+
+- How do services find each other?
+- How do we secure service communication?
+- How do we monitor service health?
+- How do we manage configuration centrally?
+
+### Supported Environments
+
+Consul works across:
+
+- Virtual Machines
+- Kubernetes
+- Hybrid environments
+- Multi-cloud deployments
+
+---
+
+## 2. Supported Operating Systems
+
+Consul supports multiple operating systems:
+
+### Linux
+- Ubuntu
+- Debian
+- RHEL
+- CentOS
+- Amazon Linux
+
+### Other Platforms
+- Windows
+- macOS
+- Kubernetes environments
+- Cloud platforms:
+ - AWS
+ - Azure
+ - GCP
+
+> Consul is written in **Go** and distributed as a single binary.
+
+---
+
+## 3. Prerequisites & Known Limitations
+
+### Prerequisites
+
+- Network connectivity between cluster nodes
+- Minimum **3 nodes** for production cluster (recommended)
+- Proper firewall configuration (ports **8300–8600**)
+- Stable DNS or IP addressing
+- TLS certificates (for secure production environments)
+
+### Known Limitations
+
+- Requires quorum for leader election
+- Performance depends on cluster size and network latency
+- Misconfigured ACLs can block cluster operations
+- Not a replacement for full configuration management tools
+
+---
+
+## 4. Architecture & Core Components
+
+Consul architecture consists of the following components:
+
+### 4.1 Servers
+
+- Maintain cluster state
+- Participate in **Raft consensus**
+- Handle leader election
+
+### 4.2 Clients (Agents)
+
+- Run on application nodes
+- Register services
+- Perform health checks
+
+### 4.3 Datacenter
+
+- Logical grouping of nodes in a specific environment
+
+### 4.4 Gossip Protocol
+
+- Used for node membership
+- Handles failure detection
+
+### 4.5 Raft Consensus
+
+- Provides strong consistency
+- Manages leader election among servers
+
+### 4.6 Key-Value Store
+
+- Stores configuration data centrally
+- Used for dynamic application configuration
+
+### 4.7 Service Mesh (Connect)
+
+- Provides secure service-to-service communication
+- Uses **mTLS (Mutual TLS)**
+- Enables zero-trust networking between services
+
+---
+
+
+
+## Role Structure
+```
+.
+├── inventory.ini
+├── site.yml
+└── roles/
+ └── consul/
+ ├── defaults/
+ │ └── main.yml
+ ├── files/
+ │ └── read-policy.hcl
+ ├── handlers/
+ │ └── main.yml
+ ├── meta/
+ │ └── main.yml
+ ├── tasks/
+ │ ├── acl.yml
+ │ ├── acl_policies.yml
+ │ ├── acl_tokens.yml
+ │ ├── config.yml
+ │ ├── directories.yml
+ │ ├── install.yml
+ │ ├── main.yml
+ │ ├── rbac.yml
+ │ └── service.yml
+ ├── templates/
+ │ ├── consul.service.j2
+ │ ├── prometheus-consul.yml.j2
+ │ ├── server.hcl.j2
+ │ └── policies/
+ │ ├── agent-policy.hcl.j2
+ │ ├── monitoring-policy.hcl.j2
+ │ ├── readonly-policy.hcl.j2
+ │ └── service-policy.hcl.j2
+ ├── tests/
+ │ └── test.yml
+ └── vars/
+ └── main.yml
+```
+
+## 5. Configuration Overview
+
+Consul can be configured using:
+
+- HCL files
+- JSON configuration files
+- Command-line flags
+- Environment variables
+
+### Important Configuration Parameters
+
+| Parameter | Description |
+|-------------------|------------|
+| `node_name` | Unique node identifier |
+| `bind_addr` | Address to bind Consul to |
+| `data_dir` | Directory for Consul data |
+| `server` | Defines server or client mode (`true/false`) |
+| `bootstrap_expect` | Number of servers expected for cluster formation |
+| `retry_join` | List of nodes to join cluster |
+| `acl` | Enables Access Control Lists |
+| `ui_config` | UI configuration settings |
+
+### ACL Configuration Includes
+
+- Enable/Disable ACLs
+- Default policies
+- Token management
+- Token persistence
+
+---
+
+## 6. Installation Flow
+### Step 1: Download Binary
+```
+wget https://releases.hashicorp.com/consul/1.17.0/consul_1.17.0_linux_amd64.zip
+```
+
+### Step 2: Unzip
+```
+unzip consul_1.17.0_linux_amd64.zip
+```
+
+### Step 3: Move Binary
+```
+sudo mv consul /usr/local/bin/
+```
+
+### Step 4: Verify Installation
+```
+consul --version
+```
+
+## 7. Running the Playbook
+```
+ansible-playbook -i inventory.ini site.yml
+```
+
+## 8. Validation & Testing
+## Check Cluster Members
+```
+consul members
+```
+## Check Leader
+```
+consul operator raft list-peers
+```
+## Check Services
+```
+consul catalog services
+```
+## Access UI
+
+Default UI URL:
+
+```
+http://:8500
+```
+
+## Vault Usage (IMPORTANT)
+
+Sensitive values like:
+
+- consul_master_token
+
+- consul_gossip_key
+
+are stored using Ansible Vault.
+
+### To Run Playbook:
+```
+ansible-playbook -i inventory.ini site.yml --ask-vault-pass
+```
+
+### OR using password file:
+```
+ansible-playbook -i inventory.ini site.yml --vault-password-file vault_pass.txt
+```
+
+## 9. Best Practices Followed
+
+- Always use minimum 3 server nodes
+
+- Enable ACLs in production
+
+- Use TLS encryption
+
+- Avoid running in -dev mode in production
+
+- Monitor health checks continuously
+
+- Secure gossip communication
+
+- Use proper token management
+
+# 10. Troubleshooting
+## Consul Not Starting
+
+- Check systemd logs
+
+```
+journalctl -u consul
+```
+## No Leader Elected
+
+- Ensure minimum quorum
+
+- Verify bootstrap_expect value
+
+- Check network connectivity
+
+## ACL Errors
+
+- Verify bootstrap token
+
+- Ensure token persistence is enabled
+
+- Check default policy
+
+## Node Not Joining
+
+- Verify retry_join
+
+- Check firewall ports
+
+- Validate bind address
+
+# 11. Conclusion
+
+HashiCorp Consul is a powerful service networking solution designed for modern distributed systems.
+
+It provides:
+
+- Reliable service discovery
+
+- Secure service communication
+
+- Centralized configuration
+
+- High availability clustering
+
+Consul simplifies infrastructure complexity and enables scalable microservices architecture.
+
+# 12. References
+
+
+| Purpose | Link |
+|---------|------|
+| Consul Official Documentation | https://developer.hashicorp.com/consul/docs |
+| Consul Installation Guide | https://developer.hashicorp.com/consul/docs/install |
+| Consul ACL Documentation | https://developer.hashicorp.com/consul/docs/security/acl |
+| Consul Service Mesh Guide | https://developer.hashicorp.com/consul/docs/connect |
+
+# 13. Author
+
+**Author**: Annem Anitha
+**Last Updated:** 25-Feb-2026
+
diff --git a/defaults/main.yml b/defaults/main.yml
index 4ece191..a243fb2 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -1,37 +1,69 @@
---
-# common
-consul_owner: consul
-consul_group: consul
-
-# consul binary
-consul_binary_dir: /usr/local/bin
-consul_binary_perm: 0440
-consul_binary_owner: root
-consul_binary_group: root
-
-# consul user
-consul_user_home: /etc/consul.d
-consul_user_shell: /bin/false
-
-# consul-hcl file
-consul_hcl_dest: /etc/consul.d/consul.hcl
-consul_hcl_mode: 0640
-
-# server-hcl file
-server_hcl_dest: /etc/consul.d/server.hcl
-server_hcl_mode: 0640
-
-# consul-service file
-consul_service_file: /etc/systemd/system/consul.service
-description: HashiCorp Consul - A service mesh solution
-documentation: https://www.consul.io/
-requires: network-online.target
-after: network-online.target
-cond_file_not_empty: /etc/consul.d/consul.hcl
-type: notify
-exec_start: /usr/local/bin/consul agent -config-dir=/etc/consul.d/
-exec_reload: /usr/local/bin/consul reload
-kill_mode: process
-restart: on-failure
-limit_file: 65536
-wanted_by: multi-user.target
+# defaults file for consul
+consul_version: "1.17.0"
+consul_user: "consul"
+consul_group: "consul"
+
+consul_install_dir: "/usr/local/bin"
+consul_data_dir: "/var/lib/consul"
+consul_config_dir: "/etc/consul.d"
+
+consul_node_name: "{{ inventory_hostname }}"
+consul_bind_addr: "{{ ansible_host }}"
+
+consul_is_server: true
+consul_bootstrap_expect: "{{ play_hosts | length }}"
+
+consul_enable_ui: true
+
+# Ports
+consul_http_port: 8500
+consul_https_port: 8501
+consul_use_tls: true
+
+# TLS
+consul_tls_server_name: "opstree.dev"
+consul_tls_verify: false
+consul_tls_enabled: false
+
+# ACL
+consul_acl_enabled: true
+consul_acl_default_policy: "deny"
+consul_acl_token_persistence: false
+consul_agent_token: ""
+
+consul_client_addr: "0.0.0.0"
+
+consul_oidc_enabled: true
+consul_public_url: "https://opstree.dev"
+
+# Internal URL to bypass Cloudflare 522. Use 127.0.0.1 if Keycloak is on the same node.
+keycloak_internal_url: "https://keycloak.opstree.dev"
+keycloak_url: "https://keycloak.opstree.dev"
+keycloak_realm: "master"
+
+consul_oidc_client_id: "consul"
+consul_oidc_client_secret: "r2kGOxYip1srrwhxiqRIAXv4bFaJroo3"
+
+consul_oidc_insecure_tls: true
+consul_oidc_max_token_ttl: "1h"
+consul_oidc_redirect_uris:
+ - "{{ consul_public_url }}/ui/oidc/callback"
+ - "http://localhost:8550/oidc/callback"
+
+# Gossip Encryption
+consul_gossip_key: ""
+
+# Monitoring
+consul_telemetry_enabled: true
+consul_prometheus_retention: "60s"
+
+# Backup & DR Configuration
+consul_backup_enabled: true
+consul_backup_minio_endpoint: "{{ lookup('env', 'MINIO_Endpoint') }}"
+consul_backup_bucket: "consul"
+consul_backups_to_keep_remote: 7
+
+# S3/MinIO backup credentials
+consul_backup_s3_access_key: "{{ lookup('env', 'MINIO_consul_accesskey') }}"
+consul_backup_s3_secret_key: "{{ lookup('env', 'MINIO_consul_secretkey') }}"
diff --git a/files/read-policy.hcl b/files/read-policy.hcl
new file mode 100644
index 0000000..f3e1480
--- /dev/null
+++ b/files/read-policy.hcl
@@ -0,0 +1,8 @@
+# Allow DNS to find nodes and services
+node_prefix "" {
+ policy = "read"
+}
+
+service_prefix "" {
+ policy = "write"
+}
diff --git a/handlers/main.yml b/handlers/main.yml
index cd1e12b..b37f139 100644
--- a/handlers/main.yml
+++ b/handlers/main.yml
@@ -1,16 +1,8 @@
---
+# handlers file for consul
-- name: daemon_reload
- systemd:
- daemon_reload: true
-
-- name: restart_consul
- service:
+- name: Restart Consul
+ ansible.builtin.systemd:
name: consul
- enabled: true
state: restarted
-
-- name: stop_consul
- service:
- name: consul
- state: stopped
+ daemon_reload: true
diff --git a/meta/main.yml b/meta/main.yml
index 5be9dd6..c65c44f 100644
--- a/meta/main.yml
+++ b/meta/main.yml
@@ -1,17 +1,34 @@
----
galaxy_info:
- author: Shatrujeet
+ author: Annem Anitha
description: Create consul cluster with any number of nodes
+ company: opstree
- min_ansible_version: 2.0
+ # If the issue tracker for your role is not on github, uncomment the
+ # next line and provide a value
+ # issue_tracker_url: http://example.com/issue/tracker
+
+ # Choose a valid license ID from https://spdx.org - some suggested licenses:
+ # - BSD-3-Clause (default)
+ # - MIT
+ # - GPL-2.0-or-later
+ # - GPL-3.0-only
+ # - Apache-2.0
+ # - CC-BY-4.0
+ license: license (GPL-2.0-or-later, MIT, etc)
+
+ min_ansible_version: 2.1
+
+ # If this a Container Enabled role, provide the minimum Ansible Container version.
+ # min_ansible_container_version:
+
+ galaxy_tags: []
+ # List tags for your role here, one per line. A tag is a keyword that describes
+ # and categorizes the role. Users find roles by searching for tags. Be sure to
+ # remove the '[]' above, if you add tags to this list.
+ #
+ # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+ # Maximum 20 tags per role.
- platforms:
- - name: Ubuntu
- versions:
- - xenial
- - precise
- - trusty
- - name: consul
- versions:
- - 1.7.2
dependencies: []
+ # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+ # if you add dependencies to this list.
diff --git a/tasks/acl.yml b/tasks/acl.yml
new file mode 100644
index 0000000..1d1fe60
--- /dev/null
+++ b/tasks/acl.yml
@@ -0,0 +1,77 @@
+---
+- name: Wait for Consul HTTPs API
+ ansible.builtin.wait_for:
+ host: "{{ consul_bind_addr }}"
+ port: "{{ consul_https_port }}"
+ delay: 15
+ timeout: 120
+
+# Check bootstrap token
+- name: Check for existing bootstrap token file
+ ansible.builtin.stat:
+ path: "{{ consul_config_dir }}/bootstrap.token"
+ register: token_file_on_disk
+
+- name: Load existing token from disk
+ ansible.builtin.slurp:
+ src: "{{ consul_config_dir }}/bootstrap.token"
+ register: slurped_token
+ become: true
+ when:
+ - token_file_on_disk.stat.exists
+ - token_file_on_disk.stat.size > 0
+
+- name: Set master token fact from file
+ ansible.builtin.set_fact:
+ consul_master_token: "{{ slurped_token.content | b64decode | trim }}"
+ when:
+ - token_file_on_disk.stat.exists
+ - slurped_token.content is defined
+
+# Bootstrap ACL
+- name: Bootstrap ACL
+ ansible.builtin.command: consul acl bootstrap -format=json
+ register: consul_bootstrap
+ run_once: true
+ failed_when: false
+ when: consul_master_token is not defined or consul_master_token == ""
+ environment:
+ CONSUL_HTTP_ADDR: "https://{{ consul_bind_addr }}:{{ consul_https_port }}"
+
+
+- name: Extract new token from bootstrap output
+ ansible.builtin.set_fact:
+ consul_master_token: "{{ (consul_bootstrap.stdout | from_json).SecretID }}"
+ run_once: true
+ no_log: true
+ when:
+ - consul_bootstrap.changed
+ - consul_bootstrap.stdout | length > 0
+ - "'SecretID' in consul_bootstrap.stdout"
+
+# Share token to all hosts
+- name: Propagate token to all hosts
+ ansible.builtin.set_fact:
+ consul_master_token: "{{ hostvars[ansible_play_hosts[0]]['consul_master_token'] }}"
+ no_log: true
+ when: consul_master_token is not defined or consul_master_token == ""
+
+# Save token
+- name: Save bootstrap token to file
+ ansible.builtin.copy:
+ content: "{{ consul_master_token }}"
+ dest: "{{ consul_config_dir }}/bootstrap.token"
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0600"
+ become: true
+ when:
+ - consul_master_token is defined
+ - consul_master_token != ""
+
+# Next tasks
+- name: Include ACL policies
+ ansible.builtin.include_tasks: acl_policies.yml
+
+- name: Include ACL tokens
+ ansible.builtin.include_tasks: acl_tokens.yml
diff --git a/tasks/acl_policies.yml b/tasks/acl_policies.yml
new file mode 100644
index 0000000..1d0f8d4
--- /dev/null
+++ b/tasks/acl_policies.yml
@@ -0,0 +1,50 @@
+---
+- name: List existing policies via Envoy TLS
+ ansible.builtin.command: consul acl policy list
+ register: existing_policies
+ run_once: true
+ become: true
+ environment:
+ CONSUL_HTTP_ADDR: "https://{{ consul_bind_addr }}:{{ consul_https_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_CACERT: "{{ consul_config_dir }}/certs/tls.crt"
+ CONSUL_CLIENT_CERT: "{{ consul_config_dir }}/certs/tls.crt"
+ CONSUL_CLIENT_KEY: "{{ consul_config_dir }}/certs/tls.key"
+ CONSUL_TLS_SERVER_NAME: "{{ consul_tls_server_name }}"
+ CONSUL_HTTP_SSL_VERIFY: "{{ consul_tls_verify | ternary('true','false') }}"
+ when: consul_tls_enabled
+
+- name: Copy policy files
+ ansible.builtin.template:
+ src: "policies/{{ item }}.hcl.j2"
+ dest: "/tmp/{{ item }}.hcl"
+ mode: "0644"
+ loop:
+ - agent-policy
+ - service-policy
+ - readonly-policy
+ - monitoring-policy
+
+- name: Create Consul policies
+ ansible.builtin.command: >
+ consul acl policy create
+ -name {{ item }}
+ -rules @/tmp/{{ item }}.hcl
+ loop:
+ - agent-policy
+ - service-policy
+ - readonly-policy
+ - monitoring-policy
+ when:
+ - consul_tls_enabled
+ - item not in existing_policies.stdout
+ run_once: true
+ become: true
+ environment:
+ CONSUL_HTTP_ADDR: "https://{{ consul_bind_addr }}:{{ consul_https_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_CACERT: "{{ consul_config_dir }}/certs/tls.crt"
+ CONSUL_CLIENT_CERT: "{{ consul_config_dir }}/certs/tls.crt"
+ CONSUL_CLIENT_KEY: "{{ consul_config_dir }}/certs/tls.key"
+ CONSUL_TLS_SERVER_NAME: "{{ consul_tls_server_name }}"
+ CONSUL_HTTP_SSL_VERIFY: "{{ consul_tls_verify | ternary('true','false') }}"
diff --git a/tasks/acl_tokens.yml b/tasks/acl_tokens.yml
new file mode 100644
index 0000000..e9a8899
--- /dev/null
+++ b/tasks/acl_tokens.yml
@@ -0,0 +1,145 @@
+---
+# Check existing tokens
+- name: Check existing tokens in consul
+ ansible.builtin.command: consul acl token list
+ register: existing_tokens
+ changed_when: false
+ run_once: true
+ environment: &consul_env
+ CONSUL_HTTP_ADDR: "https://{{ consul_bind_addr }}:{{ consul_https_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_HTTP_SSL_VERIFY: "{{ consul_tls_verify | ternary('true','false') }}"
+ CONSUL_CACERT: "{{ consul_config_dir }}/certs/tls.crt"
+
+####################################
+# Agent Token
+####################################
+
+- name: Check if agent token exists on disk
+ ansible.builtin.stat:
+ path: "{{ consul_config_dir }}/agent.token"
+ register: agent_token_stat
+
+- name: Create agent token
+ ansible.builtin.command: >
+ consul acl token create
+ -description "Agent Token"
+ -policy-name agent-policy
+ register: agent_token_output
+ when:
+ - not agent_token_stat.stat.exists
+ - "'Agent Token' not in existing_tokens.stdout"
+ run_once: true
+ environment: *consul_env
+ no_log: true
+
+- name: Save agent token
+ ansible.builtin.copy:
+ content: "{{ agent_token_output.stdout | regex_search('SecretID:\\s+([a-fA-F0-9-]+)', '\\1') | first }}"
+ dest: "{{ consul_config_dir }}/agent.token"
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0600"
+ when:
+ - not agent_token_stat.stat.exists
+ - agent_token_output.stdout is defined
+ - "'SecretID' in agent_token_output.stdout"
+ no_log: true
+
+####################################
+# Service Token
+####################################
+
+- name: Check if service token exists on disk
+ ansible.builtin.stat:
+ path: "{{ consul_config_dir }}/service.token"
+ register: service_token_stat
+
+- name: Create service token
+ ansible.builtin.command: >
+ consul acl token create
+ -description "Service Token"
+ -policy-name service-policy
+ register: service_token_output
+ when:
+ - not service_token_stat.stat.exists
+ - "'Service Token' not in existing_tokens.stdout"
+ run_once: true
+ environment: *consul_env
+ no_log: true
+
+- name: Save service token
+ ansible.builtin.copy:
+ content: "{{ service_token_output.stdout | regex_search('SecretID:\\s+([a-fA-F0-9-]+)', '\\1') | first }}"
+ dest: "{{ consul_config_dir }}/service.token"
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0600"
+ when:
+ - not service_token_stat.stat.exists
+ - agent_token_output.stdout is defined
+ - "'SecretID' in service_token_output.stdout"
+ run_once: true
+ no_log: true
+
+####################################
+# Monitoring Token Logic
+####################################
+
+- name: Check if monitoring token exists on disk (Node 1)
+ ansible.builtin.stat:
+ path: "{{ consul_config_dir }}/prometheus.token"
+ register: prom_token_stat_node1
+ run_once: true
+ delegate_to: "{{ ansible_play_hosts[0] }}"
+
+- name: Create Prometheus monitoring token if missing
+ ansible.builtin.command: >
+ consul acl token create
+ -description "Prometheus Metrics Token"
+ -policy-name monitoring-policy
+ register: prom_token_output
+ when:
+ - not prom_token_stat_node1.stat.exists
+ - "'Prometheus Metrics Token' not in existing_tokens.stdout"
+ run_once: true
+ environment: *consul_env
+
+- name: Slurp existing token if it was already on disk
+ ansible.builtin.slurp:
+ src: "{{ consul_config_dir }}/prometheus.token"
+ register: slurped_prom_token
+ when: prom_token_stat_node1.stat.exists
+ run_once: true
+ delegate_to: "{{ ansible_play_hosts[0] }}"
+
+- name: Set Prometheus token fact
+ ansible.builtin.set_fact:
+ consul_prometheus_token: >-
+ {{
+ (prom_token_output.stdout | regex_search('SecretID:\s+([a-fA-F0-9-]+)', '\1') | first)
+ if (prom_token_output.changed)
+ else (slurped_prom_token.content | b64decode | trim)
+ }}
+ run_once: true
+
+- name: Ensure Prometheus token is on all nodes
+ ansible.builtin.copy:
+ content: "{{ hostvars[ansible_play_hosts[0]]['consul_prometheus_token'] }}"
+ dest: "{{ consul_config_dir }}/prometheus.token"
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0600"
+ become: true
+
+####################################
+# Anonymous Token (Metrics Access)
+####################################
+
+- name: Allow Anonymous Token to read metrics
+ ansible.builtin.command: >
+ consul acl token update -id 00000000-0000-0000-0000-000000000002
+ -description "Anonymous Token - Metrics Access"
+ -policy-name monitoring-policy
+ run_once: true
+ environment: *consul_env
diff --git a/tasks/backup.yml b/tasks/backup.yml
new file mode 100644
index 0000000..e01c531
--- /dev/null
+++ b/tasks/backup.yml
@@ -0,0 +1,90 @@
+---
+- name: Check if AWS CLI is installed
+ ansible.builtin.command: aws --version
+ register: aws_check
+ ignore_errors: true
+ changed_when: false
+
+- name: Install AWS CLI v2
+ block:
+ - name: Install unzip
+ ansible.builtin.package:
+ name: unzip
+ state: present
+ become: true
+
+ - name: Download AWS CLI v2 bundle
+ ansible.builtin.get_url:
+ url: "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"
+ dest: "/tmp/awscliv2.zip"
+ mode: '0644'
+
+ - name: Unarchive AWS CLI bundle
+ ansible.builtin.unarchive:
+ src: "/tmp/awscliv2.zip"
+ dest: "/tmp"
+ remote_src: true
+
+ - name: Run AWS CLI installation script
+ ansible.builtin.command:
+ cmd: "/tmp/aws/install --update"
+ become: true
+ when: aws_check.failed
+
+- name: "Set backup constants"
+ ansible.builtin.set_fact:
+ consul_backup_dir: "/var/backups/consul"
+ consul_backup_filename: "consul_backup_{{ lookup('pipe', 'date +%Y%m%d_%H%M%S') }}.snap"
+
+- name: Ensure secure backup directory exists
+ ansible.builtin.file:
+ path: "{{ consul_backup_dir }}"
+ state: directory
+ owner: "{{ consul_user | default('consul') }}"
+ group: "{{ consul_group | default('consul') }}"
+ mode: "0700"
+ become: true
+
+- name: Take Consul snapshot
+ ansible.builtin.command:
+ cmd: "consul snapshot save {{ consul_backup_dir }}/{{ consul_backup_filename }}"
+ environment:
+ CONSUL_HTTP_ADDR: "https://127.0.0.1:{{ consul_https_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_HTTP_SSL_VERIFY: "false"
+ register: snapshot_result
+ become: true
+ changed_when: snapshot_result.rc == 0
+
+- name: Verify snapshot file exists before upload
+ ansible.builtin.stat:
+ path: "{{ consul_backup_dir }}/{{ consul_backup_filename }}"
+ register: snapshot_file
+
+- name: Upload backup to MinIO (S3)
+ ansible.builtin.command: >
+ aws s3 cp {{ consul_backup_dir }}/{{ consul_backup_filename }}
+ s3://{{ consul_backup_bucket }}/{{ consul_backup_filename }}
+ --endpoint-url {{ consul_backup_minio_endpoint }}
+ --no-verify-ssl
+ environment:
+ AWS_ACCESS_KEY_ID: "{{ consul_backup_s3_access_key }}"
+ AWS_SECRET_ACCESS_KEY: "{{ consul_backup_s3_secret_key }}"
+ AWS_REGION: "us-east-1"
+ AWS_EC2_METADATA_DISABLED: "true"
+ register: upload_result
+ retries: 3
+ delay: 20
+ until: upload_result.rc == 0
+ when: snapshot_file.stat.exists
+ become: true
+
+- name: Debug Upload Output
+ ansible.builtin.debug:
+ var: upload_result.stdout
+
+- name: Delete local backup file
+ ansible.builtin.file:
+ path: "{{ consul_backup_dir }}/{{ consul_backup_filename }}"
+ state: absent
+ when: upload_result is succeeded
diff --git a/tasks/config.yml b/tasks/config.yml
new file mode 100644
index 0000000..332fd44
--- /dev/null
+++ b/tasks/config.yml
@@ -0,0 +1,48 @@
+- name: Create Consul directories
+ ansible.builtin.file:
+ path: "{{ item }}"
+ state: directory
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0750"
+ loop:
+ - "{{ consul_data_dir }}"
+ - "{{ consul_config_dir }}"
+
+- name: Create TLS cert directory
+ ansible.builtin.file:
+ path: "{{ consul_config_dir }}/certs"
+ state: directory
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0750"
+ when: consul_tls_enabled
+
+- name: Copy TLS certificate
+ ansible.builtin.copy:
+ src: tls.crt
+ dest: "{{ consul_config_dir }}/certs/tls.crt"
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0644"
+ notify: Restart Consul
+ when: consul_tls_enabled
+
+- name: Copy TLS private key
+ ansible.builtin.copy:
+ src: tls.key
+ dest: "{{ consul_config_dir }}/certs/tls.key"
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0600"
+ notify: Restart Consul
+ when: consul_tls_enabled
+
+- name: Deploy Consul server configuration
+ ansible.builtin.template:
+ src: server.hcl.j2
+ dest: "{{ consul_config_dir }}/server.hcl"
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0640"
+ notify: Restart Consul
diff --git a/tasks/consul-Debian.yml b/tasks/consul-Debian.yml
deleted file mode 100644
index a68a0d7..0000000
--- a/tasks/consul-Debian.yml
+++ /dev/null
@@ -1,73 +0,0 @@
----
-
-- name: Setting private Ip of leader
- when: group_names[0] == "consul-leader"
- set_fact:
- ip_leader: "{{ ansible_default_ipv4.address }}"
-
-- name: Installing unzip
- apt:
- name: unzip
- state: present
-
-- name: Downloading archived consul binary
- when: (group_names[0] == "consul-leader") or (group_names[0] == "consul-server") or (group_names[0] == "consul-client")
- unarchive:
- src: "{{ consul_binary_url }}"
- dest: "{{ consul_binary_dir }}"
- owner: "{{ consul_binary_owner }}"
- group: "{{ consul_binary_group }}"
- remote_src: true
-
-- name: Executing command to generate encrypt key
- when: group_names[0] == "consul-leader"
- command: consul keygen
- register: encr_key
-
-- name: Stopping consul service if running
- when: (group_names[0] == "consul-leader") or (group_names[0] == "consul-server") or (group_names[0] == "consul-client")
- service:
- name: consul
- state: stopped
- ignore_errors: true
-
-- name: Including file for consul user
- when: (group_names[0] == "consul-leader") or (group_names[0] == "consul-server") or (group_names[0] == "consul-client")
- include: consul-user.yml
-
-- name: Creating a Consul service file
- when: (group_names[0] == "consul-leader") or (group_names[0] == "consul-server") or (group_names[0] == "consul-client")
- template:
- src: consul-service.j2
- dest: "{{ consul_service_file }}"
-
-- name: Creating consul.hcl file
- when: (group_names[0] == "consul-leader") or (group_names[0] == "consul-server") or (group_names[0] == "consul-client")
- template:
- src: consul-hcl.j2
- dest: "{{ consul_hcl_dest }}"
-
-- name: Creating server.hcl file for leader
- when: group_names[0] == "consul-leader"
- template:
- src: server-hcl-leader.j2
- dest: "{{ server_hcl_dest }}"
- owner: "{{ consul_owner }}"
- group: "{{ consul_group }}"
- mode: "{{ server_hcl_mode }}"
-
-- name: Creating server.hcl file for server
- when: group_names[0] == "consul-server"
- template:
- src: server-hcl.j2
- dest: "{{ server_hcl_dest }}"
- owner: "{{ consul_owner }}"
- group: "{{ consul_group }}"
- mode: "{{ server_hcl_mode }}"
-
-- name: Reloading systemd and restarting consul
- when: (group_names[0] == "consul-leader") or (group_names[0] == "consul-server") or (group_names[0] == "consul-client")
- command: /bin/true
- notify:
- - daemon_reload
- - restart_consul
diff --git a/tasks/consul-user.yml b/tasks/consul-user.yml
deleted file mode 100644
index cc7e597..0000000
--- a/tasks/consul-user.yml
+++ /dev/null
@@ -1,18 +0,0 @@
----
-- name: Adding a non-privileged user 'consul' with no shell
- user:
- name: consul
- home: "{{ consul_user_home }}"
- shell: "{{ consul_user_shell }}"
-
-- name: Checking and Removing consul storage directory if exists
- file:
- path: "{{ consul_data_dir }}"
- state: absent
-
-- name: Creating directories for consul persistent storage
- file:
- path: "{{ consul_data_dir }}"
- state: directory
- owner: "{{ consul_owner }}"
- group: "{{ consul_group }}"
diff --git a/tasks/install.yml b/tasks/install.yml
new file mode 100644
index 0000000..8da5aeb
--- /dev/null
+++ b/tasks/install.yml
@@ -0,0 +1,34 @@
+- name: Install required packages
+ ansible.builtin.apt:
+ name:
+ - unzip
+ - wget
+ - curl
+ state: present
+ update_cache: true
+
+- name: Create consul group
+ ansible.builtin.group:
+ name: "{{ consul_group }}"
+ system: true
+
+- name: Create consul user
+ ansible.builtin.user:
+ name: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ system: true
+ shell: /sbin/nologin
+ create_home: false
+
+- name: Download Consul binary
+ ansible.builtin.get_url:
+ url: "{{ consul_binary_url }}"
+ dest: "{{ consul_zip_path }}"
+ mode: "0644"
+
+- name: Unarchive Consul
+ ansible.builtin.unarchive:
+ src: "{{ consul_zip_path }}"
+ dest: "{{ consul_install_dir }}"
+ remote_src: true
+ mode: "0755"
diff --git a/tasks/main.yml b/tasks/main.yml
index 543501b..5c759c8 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -1,5 +1,25 @@
---
+- name: Include installation tasks
+ ansible.builtin.include_tasks: install.yml
+
+- name: Include configuration tasks
+ ansible.builtin.include_tasks: config.yml
-- name: Include OS Specific setup file
- when: ansible_os_family == "Debian"
- include: consul-Debian.yml
+- name: Include service tasks
+ ansible.builtin.include_tasks: service.yml
+
+- name: Include ACL tasks
+ ansible.builtin.include_tasks: acl.yml
+ when: consul_acl_enabled
+
+- name: Include RBAC tasks
+ ansible.builtin.include_tasks: rbac.yml
+ when: consul_acl_enabled
+
+- name: Include Backup tasks
+ ansible.builtin.include_tasks: backup.yml
+ when: consul_backup_enabled | bool
+
+- name: Include OIDC SSO tasks
+ ansible.builtin.include_tasks: oidc.yml
+ when: consul_oidc_enabled | bool
diff --git a/tasks/oidc.yml b/tasks/oidc.yml
new file mode 100644
index 0000000..9a3b5b0
--- /dev/null
+++ b/tasks/oidc.yml
@@ -0,0 +1,65 @@
+---
+# ✅ Step 1: Check if the existing method exists
+- name: Check current Keycloak auth method
+ ansible.builtin.uri:
+ url: "http://127.0.0.1:8500/v1/acl/auth-method/keycloak"
+ method: GET
+ headers:
+ X-Consul-Token: "{{ consul_master_token }}"
+ status_code: [200, 404]
+ register: existing_method
+ run_once: true
+
+# ✅ Step 2: Delete ONLY if it is not the correct configuration
+- name: Delete existing method if not jwt
+ ansible.builtin.uri:
+ url: "http://127.0.0.1:8500/v1/acl/auth-method/keycloak"
+ method: DELETE
+ headers:
+ X-Consul-Token: "{{ consul_master_token }}"
+ status_code: [200, 204]
+ run_once: true
+ when:
+ - existing_method.status == 200
+ - existing_method.json.Type != 'jwt'
+
+# ✅ Step 3: Create or Update the JWT Auth Method (Updated for UI Visibility)
+- name: Upsert Keycloak JWT Auth Method via API
+ ansible.builtin.uri:
+ url: "http://127.0.0.1:8500/v1/acl/auth-method/keycloak"
+ method: PUT
+ headers:
+ X-Consul-Token: "{{ consul_master_token }}"
+ body_format: json
+ body:
+ Name: "keycloak"
+ Type: "jwt"
+ Description: "JWT Auth via Keycloak"
+ Config:
+ JWKSURL: "{{ keycloak_internal_url }}/realms/{{ keycloak_realm }}/protocol/openid-connect/certs"
+ BoundIssuer: "{{ keycloak_url }}/realms/{{ keycloak_realm }}"
+ JWTSupportedAlgs: ["RS256"]
+ BoundAudiences: ["{{ consul_oidc_client_id }}"]
+ ClaimMappings:
+ preferred_username: "username"
+ ListClaimMappings:
+ groups: "groups"
+ status_code: [200, 201, 204]
+ run_once: true
+
+# ✅ Step 4: Create Binding Rule for SSO Users
+- name: Create Binding Rule for SSO Users
+ ansible.builtin.command: >
+ consul acl binding-rule create
+ -method="keycloak"
+ -bind-type="role"
+ -bind-name="readonly-role"
+ -selector='list.groups contains "consul-users"'
+ environment:
+ CONSUL_HTTP_ADDR: "http://127.0.0.1:8500"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ run_once: true
+ register: binding_rule_out
+ failed_when:
+ - binding_rule_out.rc != 0
+ - "'already exists' not in binding_rule_out.stderr"
diff --git a/tasks/rbac.yml b/tasks/rbac.yml
new file mode 100644
index 0000000..b8d8c0d
--- /dev/null
+++ b/tasks/rbac.yml
@@ -0,0 +1,88 @@
+---
+- name: Copy read policy file
+ ansible.builtin.copy:
+ src: read-policy.hcl
+ dest: /tmp/read-policy.hcl
+ mode: "0644"
+
+- name: Check existing policies
+ ansible.builtin.command: consul acl policy list
+ register: policy_list
+ changed_when: false
+ run_once: true
+ environment:
+ CONSUL_HTTP_ADDR: "{{ 'https' if consul_tls_enabled else 'http' }}://{{ consul_bind_addr }}:{{ consul_https_port if consul_tls_enabled else consul_http_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_HTTP_SSL_VERIFY: "{{ consul_tls_verify | ternary('true','false') }}"
+
+- name: Create read policy
+ ansible.builtin.command: >
+ consul acl policy create
+ -name read-policy
+ -rules @/tmp/read-policy.hcl
+ when: "'read-policy' not in policy_list.stdout"
+ run_once: true
+ environment:
+ CONSUL_HTTP_ADDR: "{{ 'https' if consul_tls_enabled else 'http' }}://{{ consul_bind_addr }}:{{ consul_https_port if consul_tls_enabled else consul_http_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_HTTP_SSL_VERIFY: "{{ consul_tls_verify | ternary('true','false') }}"
+
+- name: Check existing roles
+ ansible.builtin.command: consul acl role list
+ register: role_list
+ changed_when: false
+ run_once: true
+ environment:
+ CONSUL_HTTP_ADDR: "{{ 'https' if consul_tls_enabled else 'http' }}://{{ consul_bind_addr }}:{{ consul_https_port if consul_tls_enabled else consul_http_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_HTTP_SSL_VERIFY: "{{ consul_tls_verify | ternary('true','false') }}"
+
+- name: Create read role
+ ansible.builtin.command: >
+ consul acl role create
+ -name read-role
+ -policy-name read-policy
+ when: "'read-role' not in role_list.stdout"
+ run_once: true
+ environment:
+ CONSUL_HTTP_ADDR: "{{ 'https' if consul_tls_enabled else 'http' }}://{{ consul_bind_addr }}:{{ consul_https_port if consul_tls_enabled else consul_http_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_HTTP_SSL_VERIFY: "{{ consul_tls_verify | ternary('true','false') }}"
+
+# ------------------------------------------------
+# APPLICATION TOKEN (NO DUPLICATES)
+# ------------------------------------------------
+
+- name: Check if application token exists on disk
+ ansible.builtin.stat:
+ path: "{{ consul_config_dir }}/app.token"
+ register: app_token_stat
+ run_once: true
+
+- name: Create application token
+ ansible.builtin.command: >
+ consul acl token create
+ -description "App Read Token"
+ -role-name read-role
+ register: app_token_output
+ when: not app_token_stat.stat.exists
+ run_once: true
+ no_log: true
+ environment:
+ CONSUL_HTTP_ADDR: "{{ 'https' if consul_tls_enabled else 'http' }}://{{ consul_bind_addr }}:{{ consul_https_port if consul_tls_enabled else consul_http_port }}"
+ CONSUL_HTTP_TOKEN: "{{ consul_master_token }}"
+ CONSUL_HTTP_SSL_VERIFY: "{{ consul_tls_verify | ternary('true','false') }}"
+
+- name: Save application token
+ ansible.builtin.copy:
+ content: "{{ app_token_output.stdout | regex_search('SecretID:\\s+([a-fA-F0-9-]+)', '\\1') | first }}"
+ dest: "{{ consul_config_dir }}/app.token"
+ owner: "{{ consul_user }}"
+ group: "{{ consul_group }}"
+ mode: "0600"
+ when:
+ - not app_token_stat.stat.exists
+ - app_token_output.stdout is defined
+ - "'SecretID' in app_token_output.stdout"
+ run_once: true
+ no_log: true
diff --git a/tasks/service.yml b/tasks/service.yml
new file mode 100644
index 0000000..cf1e6a8
--- /dev/null
+++ b/tasks/service.yml
@@ -0,0 +1,13 @@
+- name: Deploy systemd service
+ ansible.builtin.template:
+ src: consul.service.j2
+ dest: /etc/systemd/system/consul.service
+ mode: "0644"
+ notify:
+ - Restart Consul
+
+- name: Enable and start Consul
+ ansible.builtin.systemd:
+ name: consul
+ enabled: true
+ state: started
diff --git a/templates/consul-hcl.j2 b/templates/consul-hcl.j2
deleted file mode 100644
index 98fd01d..0000000
--- a/templates/consul-hcl.j2
+++ /dev/null
@@ -1,7 +0,0 @@
-datacenter = "{{ datacenter }}"
-data_dir = "{{ consul_data_dir }}"
-encrypt = "{{ hostvars[groups['consul-leader'][0]].encr_key.stdout }}"
-retry_join = ["{{ hostvars[groups['consul-leader'][0]].ip_leader }}"]
-performance {
- raft_multiplier = {{ raft_mul }}
-}
diff --git a/templates/consul-service.j2 b/templates/consul-service.j2
deleted file mode 100644
index e25a5de..0000000
--- a/templates/consul-service.j2
+++ /dev/null
@@ -1,19 +0,0 @@
-[Unit]
-Description="{{ description }}"
-Documentation={{ documentation }}
-Requires={{ requires }}
-After={{ after }}
-ConditionFileNotEmpty={{ cond_file_not_empty }}
-
-[Service]
-Type={{ type }}
-User={{ consul_owner }}
-Group={{ consul_group }}
-ExecStart={{ exec_start }}
-ExecReload={{ exec_reload }}
-KillMode={{ kill_mode }}
-Restart={{ restart }}
-LimitNOFILE={{ limit_file }}
-
-[Install]
-WantedBy={{ wanted_by }}
diff --git a/templates/consul.service.j2 b/templates/consul.service.j2
new file mode 100644
index 0000000..281d3cc
--- /dev/null
+++ b/templates/consul.service.j2
@@ -0,0 +1,16 @@
+[Unit]
+Description=Consul Agent
+Requires=network-online.target
+After=network-online.target
+
+[Service]
+User={{ consul_user }}
+Group={{ consul_group }}
+ExecStart={{ consul_install_dir }}/consul agent -config-dir={{ consul_config_dir }}
+ExecReload=/bin/kill -HUP $MAINPID
+KillSignal=SIGINT
+Restart=on-failure
+LimitNOFILE=65536
+
+[Install]
+WantedBy=multi-user.target
diff --git a/templates/policies/agent-policy.hcl.j2 b/templates/policies/agent-policy.hcl.j2
new file mode 100644
index 0000000..6ad8420
--- /dev/null
+++ b/templates/policies/agent-policy.hcl.j2
@@ -0,0 +1,11 @@
+node_prefix "" {
+ policy = "write"
+}
+
+service_prefix "" {
+ policy = "read"
+}
+
+agent_prefix "" {
+ policy = "write"
+}
diff --git a/templates/policies/monitoring-policy.hcl.j2 b/templates/policies/monitoring-policy.hcl.j2
new file mode 100644
index 0000000..d96bc6d
--- /dev/null
+++ b/templates/policies/monitoring-policy.hcl.j2
@@ -0,0 +1,9 @@
+agent_prefix "" {
+ policy = "read"
+}
+node_prefix "" {
+ policy = "read"
+}
+service_prefix "" {
+ policy = "read"
+}
diff --git a/templates/policies/readonly-policy.hcl.j2 b/templates/policies/readonly-policy.hcl.j2
new file mode 100644
index 0000000..09b4b13
--- /dev/null
+++ b/templates/policies/readonly-policy.hcl.j2
@@ -0,0 +1,11 @@
+node_prefix "" {
+ policy = "read"
+}
+
+service_prefix "" {
+ policy = "read"
+}
+
+key_prefix "" {
+ policy = "read"
+}
diff --git a/templates/policies/service-policy.hcl.j2 b/templates/policies/service-policy.hcl.j2
new file mode 100644
index 0000000..47bd12c
--- /dev/null
+++ b/templates/policies/service-policy.hcl.j2
@@ -0,0 +1,7 @@
+service_prefix "" {
+ policy = "write"
+}
+
+node_prefix "" {
+ policy = "read"
+}
diff --git a/templates/prometheus-consul.yml.j2 b/templates/prometheus-consul.yml.j2
new file mode 100644
index 0000000..842060e
--- /dev/null
+++ b/templates/prometheus-consul.yml.j2
@@ -0,0 +1,27 @@
+# Prometheus scrape configuration for Consul Cluster
+scrape_configs:
+ - job_name: 'consul-cluster'
+ scheme: https
+ metrics_path: '/v1/agent/metrics'
+ params:
+ format: ['prometheus']
+ tls_config:
+ insecure_skip_verify: true
+ # This matches your Envoy DNS name
+ server_name: "consul.opstree.dev"
+
+ # This pulls the token that was generated in your acl_tokens.yml task
+ bearer_token: "{{ consul_prometheus_token }}"
+
+ static_configs:
+ - targets:
+{% for host in play_hosts %}
+ - "{{ hostvars[host]['ansible_host'] }}:8501"
+{% endfor %}
+
+ # This cleans up the labels in Prometheus so you see the IP instead of IP:8501
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ regex: '([^:]+)(?::\d+)?'
+ replacement: '${1}'
diff --git a/templates/server-hcl-leader.j2 b/templates/server-hcl-leader.j2
deleted file mode 100644
index 8e773c8..0000000
--- a/templates/server-hcl-leader.j2
+++ /dev/null
@@ -1,2 +0,0 @@
-server = true
-bootstrap_expect = 1
diff --git a/templates/server-hcl.j2 b/templates/server-hcl.j2
deleted file mode 100644
index cb15f46..0000000
--- a/templates/server-hcl.j2
+++ /dev/null
@@ -1 +0,0 @@
-server = true
diff --git a/templates/server.hcl.j2 b/templates/server.hcl.j2
new file mode 100644
index 0000000..067b339
--- /dev/null
+++ b/templates/server.hcl.j2
@@ -0,0 +1,54 @@
+node_name = "{{ consul_node_name }}"
+bind_addr = "{{ consul_bind_addr }}"
+client_addr = "{{ consul_client_addr }}"
+data_dir = "{{ consul_data_dir }}"
+
+encrypt = "{{ consul_gossip_key }}"
+
+server = {{ consul_is_server | lower }}
+bootstrap_expect = {{ consul_bootstrap_expect }}
+
+ui_config {
+ enabled = {{ consul_enable_ui | lower }}
+}
+
+retry_join = [
+{% for host in play_hosts %}
+ "{{ hostvars[host]['ansible_host'] | default(host) }}"{% if not loop.last %},{% endif %}
+{% endfor %}
+]
+
+telemetry {
+ prometheus_retention_time = "{{ consul_prometheus_retention }}"
+ disable_hostname = true
+}
+
+acl {
+ enabled = {{ consul_acl_enabled | lower }}
+ default_policy = "{{ consul_acl_default_policy }}"
+ enable_token_persistence = {{ consul_acl_token_persistence | lower }}
+
+ tokens {
+ # Added initial_management for SSO UI functionality
+ initial_management = "{{ consul_master_token }}"
+ {% if consul_agent_token is defined and consul_agent_token != "" %}
+ agent = "{{ consul_agent_token }}"
+ {% endif %}
+ }
+}
+
+ports {
+ http = {{ consul_http_port }}
+ https = {{ consul_https_port }}
+}
+
+tls {
+ defaults {
+ ca_file = "{{ consul_config_dir }}/certs/tls.crt"
+ cert_file = "{{ consul_config_dir }}/certs/tls.crt"
+ key_file = "{{ consul_config_dir }}/certs/tls.key"
+
+ verify_incoming = false
+ verify_outgoing = false
+ }
+}
diff --git a/tests/test.yml b/tests/test.yml
new file mode 100644
index 0000000..eca63c9
--- /dev/null
+++ b/tests/test.yml
@@ -0,0 +1,6 @@
+- name: Deploy Consul Cluster
+ hosts: all
+ become: true
+ roles:
+ - consul-role
+
diff --git a/vars/main.yml b/vars/main.yml
index cc4abb6..5092e2d 100644
--- a/vars/main.yml
+++ b/vars/main.yml
@@ -1,10 +1,28 @@
---
-# consul binary
-consul_binary_url: https://releases.hashicorp.com/consul/1.7.2/consul_1.7.2_linux_amd64.zip
+# vars file for consul
-# consul persistent storage
-consul_data_dir: /opt/consul
-# consul-hcl
-datacenter: dc1
-raft_mul: 1
+# Installation variables
+consul_binary_url: "https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version }}_linux_amd64.zip"
+consul_zip_path: "/tmp/consul_{{ consul_version }}.zip"
+
+
+# Sensitive Keys
+consul_master_token: !vault |
+ $ANSIBLE_VAULT;1.1;AES256
+ 64363638396462636134353637383865643931373664373034623536366134623235306438356164
+ 3665393634643363396437333436363936303835343166650a343639663665373161376433613932
+ 62343336303839303038376437393965396165633039636339326363396530636564313630326265
+ 3134613636396265300a633636396164363365353066633964306534316163303264623764643532
+ 39323234346661383638313135346537613530333537636461343631653639663232373632646665
+ 3634393638313962393166316439633230643331383665623634
+
+
+consul_gossip_key: !vault |
+ $ANSIBLE_VAULT;1.1;AES256
+ 63666262323562663362346564363332353364663338396337333031616437373863316130613631
+ 3966663365653036316364323537386530643666653564370a653438393136666436396230326464
+ 39393738346630353432623434353063666161653832346438343566366664303464353334306532
+ 3937633962373832620a353432336365323433306165633264363638353235643666633564393761
+ 61353532316133616630396362333265316132333038323639396139333761326537636330346334
+ 3336343330373533333435306264313430313662346364643637