Skip to content

Commit 721bec1

Browse files
committed
feat: add SASL support to operation playbooks and new SASL playbooks
Updates operation playbooks to support SASL-enabled clusters: - operation-rolling-restart.yml: Add rpk_opts/rpk_admin_opts for SASL auth - operation-apply-license.yml: Add SASL support for license application - operation-configure-logging.yml: Add SASL support for logging config New playbooks: - provision-cluster-tls-sasl.yml: Deploy TLS + SASL enabled clusters - manage-sasl-users.yml: Manage SASL users and ACLs via user_management role Usage: Pass SASL credentials via extra vars: -e "kafka_enable_authorization=true" -e "admin_api_require_auth=true" -e "sasl_superuser_username=admin" -e "sasl_superuser_password=<password>"
1 parent 4206e55 commit 721bec1

File tree

6 files changed

+364
-15
lines changed

6 files changed

+364
-15
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,36 @@ ansible-playbook ansible/deploy-client.yml --private-key ~/.ssh/id_rsa
6363

6464
The playbooks can all be run in any order. However they are designed with the assumption that you will run only either the TLS or non TLS playbooks, not both. Currently we do not support converting a cluster from non-TLS to TLS or vice versa.
6565

66+
## SASL Authentication Deployments
67+
68+
### TLS + SASL Cluster
69+
70+
Deploy a cluster with both TLS encryption and SASL authentication:
71+
72+
```bash
73+
export REDPANDA_SASL_PASSWORD="your-secure-password"
74+
export SR_SERVICE_PASSWORD="schema-registry-password"
75+
export PP_SERVICE_PASSWORD="pandaproxy-password"
76+
77+
ansible-playbook ansible/provision-cluster-tls-sasl.yml \
78+
--private-key ~/.ssh/id_rsa \
79+
--inventory artifacts/hosts_gcp_$DEPLOYMENT_PREFIX.ini
80+
```
81+
82+
### Managing Users and ACLs
83+
84+
After deploying a SASL-enabled cluster, you can manage additional users and ACLs:
85+
86+
```bash
87+
export REDPANDA_SASL_PASSWORD="your-admin-password"
88+
export PRODUCER_APP_PASSWORD="producer-password"
89+
export CONSUMER_APP_PASSWORD="consumer-password"
90+
91+
ansible-playbook ansible/manage-sasl-users.yml \
92+
--private-key ~/.ssh/id_rsa \
93+
--inventory artifacts/hosts_gcp_$DEPLOYMENT_PREFIX.ini
94+
```
95+
6696
## Additional Documentation
6797

6898
More information on consuming this collection

ansible/manage-sasl-users.yml

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
# Idempotent SASL User, Role, and ACL Management
3+
#
4+
# This playbook manages users, roles, and ACLs in a declarative way.
5+
# It queries existing state and only makes necessary changes.
6+
#
7+
# Usage:
8+
# export REDPANDA_SASL_PASSWORD="admin-password"
9+
# ansible-playbook ansible/manage-sasl-users.yml \
10+
# --private-key ~/.ssh/id_rsa \
11+
# --inventory hosts.ini \
12+
# -e @path/to/users.yml # Optional: override users/roles/acls from file
13+
#
14+
- name: Manage SASL Users, Roles, and ACLs
15+
hosts: redpanda[0]
16+
become: true
17+
vars:
18+
# Connection settings (must match cluster configuration)
19+
enable_tls: true
20+
redpanda_truststore_file: "/etc/redpanda/certs/truststore.pem"
21+
22+
# Admin credentials
23+
sasl_admin_username: "admin"
24+
sasl_admin_password: "{{ lookup('env', 'REDPANDA_SASL_PASSWORD') }}"
25+
26+
# =========================================================================
27+
# USERS
28+
# =========================================================================
29+
# Define users to manage. Set state: absent to delete.
30+
# Set update_password: true to force password update for existing users.
31+
sasl_users:
32+
- username: "producer_app"
33+
password: "{{ lookup('env', 'PRODUCER_APP_PASSWORD') | default('producer-secret', true) }}"
34+
mechanism: "SCRAM-SHA-256"
35+
state: present
36+
37+
- username: "consumer_app"
38+
password: "{{ lookup('env', 'CONSUMER_APP_PASSWORD') | default('consumer-secret', true) }}"
39+
mechanism: "SCRAM-SHA-256"
40+
state: present
41+
42+
# Example: delete a user
43+
# - username: "old_user"
44+
# state: absent
45+
46+
# =========================================================================
47+
# ROLES (Enterprise Feature - RBAC)
48+
# =========================================================================
49+
# Define roles and their members
50+
sasl_roles: []
51+
# Example:
52+
# - name: "producers"
53+
# state: present
54+
# members:
55+
# - "producer_app"
56+
#
57+
# - name: "old_role"
58+
# state: absent
59+
60+
# =========================================================================
61+
# KAFKA ACLs
62+
# =========================================================================
63+
# Define ACLs for Kafka resources (topics, groups, cluster, transactional-id)
64+
# Supports: multiple operations per ACL, multiple resources per ACL, role-based ACLs
65+
sasl_acls:
66+
# Producer: write and describe to events-* topics (multiple operations)
67+
- principal: "User:producer_app"
68+
resource_type: topic
69+
resource_name: "events-"
70+
pattern_type: prefixed
71+
operation:
72+
- write
73+
- describe
74+
permission: allow
75+
state: present
76+
77+
# Consumer: read and describe from events-* topics (multiple operations)
78+
- principal: "User:consumer_app"
79+
resource_type: topic
80+
resource_name: "events-"
81+
pattern_type: prefixed
82+
operation:
83+
- read
84+
- describe
85+
permission: allow
86+
state: present
87+
88+
# Consumer: use consumer groups
89+
- principal: "User:consumer_app"
90+
resource_type: group
91+
resource_name: "consumer-"
92+
pattern_type: prefixed
93+
operation: read
94+
permission: allow
95+
state: present
96+
97+
# Example: multiple topics in one ACL
98+
# - principal: "User:app_user"
99+
# resource_type: topic
100+
# resource_name:
101+
# - "orders"
102+
# - "payments"
103+
# - "notifications"
104+
# operation: read
105+
# permission: allow
106+
# state: present
107+
108+
# Example: role-based ACL (Enterprise RBAC)
109+
# - role: "producers"
110+
# resource_type: topic
111+
# resource_name: "events-"
112+
# pattern_type: prefixed
113+
# operation: write
114+
# permission: allow
115+
# state: present
116+
117+
# Example: delete an ACL
118+
# - principal: "User:old_user"
119+
# resource_type: topic
120+
# resource_name: "old-topic"
121+
# pattern_type: literal
122+
# operation: all
123+
# permission: allow
124+
# state: absent
125+
126+
# =========================================================================
127+
# SCHEMA REGISTRY ACLs (Enterprise Feature)
128+
# =========================================================================
129+
# Define ACLs for Schema Registry resources
130+
schema_registry_acls:
131+
# Producer: write schemas for events-* subjects
132+
- principal: "User:producer_app"
133+
resource_type: subject
134+
resource_name: "events-"
135+
pattern_type: prefixed
136+
operation: write
137+
permission: allow
138+
state: present
139+
140+
# Consumer: read schemas for events-* subjects
141+
- principal: "User:consumer_app"
142+
resource_type: subject
143+
resource_name: "events-"
144+
pattern_type: prefixed
145+
operation: read
146+
permission: allow
147+
state: present
148+
149+
# Example: Schema admin with global access
150+
# - principal: "User:schema_admin"
151+
# resource_type: global
152+
# operation: all
153+
# permission: allow
154+
# state: present
155+
156+
roles:
157+
- role: redpanda.cluster.user_management

ansible/operation-apply-license.yml

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,63 @@
55
vars:
66
rpk_bin: rpk
77

8+
# SASL Authentication (optional)
9+
# Set kafka_enable_authorization=true and provide credentials for SASL-enabled clusters
10+
kafka_enable_authorization: false
11+
admin_api_require_auth: false
12+
sasl_superuser_username: "admin"
13+
sasl_superuser_password: ""
14+
15+
# TLS Configuration (optional)
16+
enable_tls: false
17+
redpanda_truststore_file: /etc/redpanda/certs/truststore.pem
18+
19+
# Kafka port
20+
redpanda_kafka_port: 9092
21+
22+
# Build rpk options based on configuration
23+
rpk_opts: >-
24+
-X brokers={{ hostvars[inventory_hostname].private_ip | default(ansible_default_ipv4.address) }}:{{ redpanda_kafka_port }}
25+
{% if enable_tls | default(false) %}-X tls.enabled=true -X tls.ca={{ redpanda_truststore_file }}{% endif %}
26+
{% if kafka_enable_authorization | default(false) and sasl_superuser_password != '' %}-X user={{ sasl_superuser_username }} -X pass={{ sasl_superuser_password }} -X sasl.mechanism=SCRAM-SHA-256{% endif %}
27+
28+
# Admin API options
29+
rpk_admin_opts: >-
30+
{% if enable_tls | default(false) %}-X admin.tls.enabled=true -X admin.tls.ca={{ redpanda_truststore_file }}{% endif %}
31+
{% if admin_api_require_auth | default(false) and sasl_superuser_password != '' %}-X user={{ sasl_superuser_username }} -X pass={{ sasl_superuser_password }}{% endif %}
32+
833
tasks:
934
- name: Check cluster health
1035
ansible.builtin.shell: |
11-
{{ rpk_bin }} cluster health | grep -i 'healthy:' | tr -d '[:space:]' | awk -F ':' '{print tolower($2)}'
36+
{{ rpk_bin }} cluster health {{ rpk_opts }} {{ rpk_admin_opts }} | grep -i 'healthy:' | tr -d '[:space:]' | awk -F ':' '{print tolower($2)}'
1237
register: health_check
1338
run_once: true
1439
failed_when: "health_check.stdout != 'true'"
1540
changed_when: false
41+
no_log: "{{ kafka_enable_authorization | default(false) }}"
1642

43+
# License from string (direct value)
1744
- name: Set Redpanda license (string)
18-
ansible.builtin.command: rpk cluster license set {{ redpanda_license }}
45+
ansible.builtin.shell: "{{ rpk_bin }} cluster license set {{ redpanda_license }} {{ rpk_opts }} {{ rpk_admin_opts }}"
1946
run_once: true
2047
changed_when: false
2148
when:
2249
- redpanda_license is defined
50+
no_log: true
2351

52+
# License from file path (file must exist on remote node)
2453
- name: Set Redpanda license (path)
25-
ansible.builtin.command: rpk cluster license set --path {{ redpanda_license_path }}
54+
ansible.builtin.shell: "{{ rpk_bin }} cluster license set --path {{ redpanda_license_path }} {{ rpk_opts }} {{ rpk_admin_opts }}"
2655
changed_when: false
2756
run_once: true
2857
when:
2958
- redpanda_license_path is defined
59+
no_log: "{{ kafka_enable_authorization | default(false) }}"
3060

3161
- name: Check broker status
3262
ansible.builtin.shell: |
33-
{{ rpk_bin }} redpanda admin brokers list | grep -q 'active.*true'
63+
{{ rpk_bin }} redpanda admin brokers list {{ rpk_admin_opts }} | grep -q 'active.*true'
3464
register: broker_status
3565
changed_when: false
3666
failed_when: broker_status.rc != 0
67+
no_log: "{{ kafka_enable_authorization | default(false) }}"

ansible/operation-configure-logging.yml

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,41 @@
55
vars:
66
rpk_bin: rpk
77

8+
# SASL Authentication (optional)
9+
# Set kafka_enable_authorization=true and provide credentials for SASL-enabled clusters
10+
kafka_enable_authorization: false
11+
admin_api_require_auth: false
12+
sasl_superuser_username: "admin"
13+
sasl_superuser_password: ""
14+
15+
# TLS Configuration (optional)
16+
enable_tls: false
17+
redpanda_truststore_file: /etc/redpanda/certs/truststore.pem
18+
19+
# Kafka port
20+
redpanda_kafka_port: 9092
21+
22+
# Build rpk options based on configuration
23+
rpk_opts: >-
24+
-X brokers={{ hostvars[inventory_hostname].private_ip | default(ansible_default_ipv4.address) }}:{{ redpanda_kafka_port }}
25+
{% if enable_tls | default(false) %}-X tls.enabled=true -X tls.ca={{ redpanda_truststore_file }}{% endif %}
26+
{% if kafka_enable_authorization | default(false) and sasl_superuser_password != '' %}-X user={{ sasl_superuser_username }} -X pass={{ sasl_superuser_password }} -X sasl.mechanism=SCRAM-SHA-256{% endif %}
27+
28+
# Admin API options
29+
rpk_admin_opts: >-
30+
{% if enable_tls | default(false) %}-X admin.tls.enabled=true -X admin.tls.ca={{ redpanda_truststore_file }}{% endif %}
31+
{% if admin_api_require_auth | default(false) and sasl_superuser_password != '' %}-X user={{ sasl_superuser_username }} -X pass={{ sasl_superuser_password }}{% endif %}
32+
833
tasks:
934
- name: Check cluster health
1035
ansible.builtin.shell: |
1136
set -o pipefail
12-
{{ rpk_bin }} cluster health | grep -i 'healthy:' | tr -d '[:space:]' | awk -F ':' '{print tolower($2)}'
37+
{{ rpk_bin }} cluster health {{ rpk_opts }} {{ rpk_admin_opts }} | grep -i 'healthy:' | tr -d '[:space:]' | awk -F ':' '{print tolower($2)}'
1338
register: health_check
1439
run_once: true
1540
failed_when: "health_check.stdout != 'true'"
1641
changed_when: false
42+
no_log: "{{ kafka_enable_authorization | default(false) }}"
1743

1844
- name: Apply logging role
1945
ansible.builtin.include_role:
@@ -59,10 +85,11 @@
5985
- name: Check broker status
6086
ansible.builtin.shell: |
6187
set -o pipefail
62-
{{ rpk_bin }} redpanda admin brokers list | grep -q 'active.*true'
88+
{{ rpk_bin }} redpanda admin brokers list {{ rpk_admin_opts }} | grep -q 'active.*true'
6389
register: broker_status
6490
changed_when: false
6591
failed_when: broker_status.rc != 0
92+
no_log: "{{ kafka_enable_authorization | default(false) }}"
6693

6794
- name: Display logging configuration summary
6895
ansible.builtin.debug:

0 commit comments

Comments
 (0)