feat(ceph): add read-only metrics-worker RGW admin user + keys (#188)

This commit is contained in:
Andy Molenda
2026-06-26 14:07:49 +00:00
committed by GitHub
parent fa1683c9c6
commit 983e061d01
5 changed files with 72 additions and 2 deletions
@@ -93,6 +93,15 @@ ceph_rgw_port: 443
ceph_rgw_s3_user_uid: svc-yucca-restic
ceph_rgw_s3_user_display_name: "yucca/restic service account"
# Metrics-worker RGW admin (read-only). Keys TF-minted in 1P
# (SIETCH_METRICS_WORKER_{ACCESS,SECRET}_KEY); the metrics worker scrapes RGW
# usage/bucket/user stats via the admin ops API. Read-only admin caps only.
ceph_rgw_metrics_user_uid: metrics-worker
ceph_rgw_metrics_user_display_name: "yucca/metrics-worker RGW admin (read-only)"
ceph_rgw_metrics_user_access_key: "{{ vault_metrics_worker_access_key }}"
ceph_rgw_metrics_user_secret_key: "{{ vault_metrics_worker_secret_key }}"
ceph_rgw_metrics_user_caps: "buckets=read;usage=read;metadata=read;users=read"
# --- RGW DNS + TLS ---
# Virtual-hosted S3 support: setting rgw_dns_name tells RGW to strip this
# suffix from the Host header and treat the remainder as the bucket name.
@@ -573,6 +573,54 @@
changed_when: true
no_log: true
# --- Step 14.5: Metrics-worker RGW admin user (read-only) ---
#
# A dedicated RGW user the metrics worker uses to scrape usage/bucket/user
# stats via the radosgw admin ops API. Keys are TF-minted in 1P
# (<CLUSTER>_METRICS_WORKER_{ACCESS,SECRET}_KEY) and passed here so the consumer
# is pre-configured with matching credentials. Read-only admin caps only -- it
# can read stats but cannot mutate buckets or users.
- name: Check if metrics-worker RGW user exists
ansible.builtin.command: "radosgw-admin user info --uid={{ ceph_rgw_metrics_user_uid }}"
register: metrics_user_check
when: inventory_hostname in groups['ceph_bootstrap']
changed_when: false
failed_when: false
- name: Create metrics-worker RGW user with predetermined keys — {{ ceph_rgw_metrics_user_uid }}
ansible.builtin.command: >
radosgw-admin user create
--uid={{ ceph_rgw_metrics_user_uid }}
--display-name='{{ ceph_rgw_metrics_user_display_name }}'
--access-key='{{ ceph_rgw_metrics_user_access_key }}'
--secret-key='{{ ceph_rgw_metrics_user_secret_key }}'
--max-buckets=0
register: metrics_user_create
when:
- inventory_hostname in groups['ceph_bootstrap']
- metrics_user_check.rc != 0
changed_when: true
no_log: true
- name: Ensure metrics-worker RGW user has read-only admin caps
ansible.builtin.shell: |
set -o pipefail
CAPS=$(radosgw-admin user info --uid={{ ceph_rgw_metrics_user_uid }} --format json 2>/dev/null \
| python3 -c "import sys,json; print(len(json.load(sys.stdin).get('caps',[])))")
if [ "$CAPS" -lt 4 ]; then
radosgw-admin caps add --uid={{ ceph_rgw_metrics_user_uid }} \
--caps='{{ ceph_rgw_metrics_user_caps }}' >/dev/null 2>&1
echo "CHANGED"
else
echo "OK"
fi
args:
executable: /bin/bash
when: inventory_hostname in groups['ceph_bootstrap']
register: metrics_caps
changed_when: "'CHANGED' in metrics_caps.stdout"
# --- Step 15: Converge S3 user keys to the 1P canonical key (gated rotation) ---
#
# For clusters that predate the predetermined-keys pattern, the user exists
+8 -2
View File
@@ -28,8 +28,14 @@ locals {
# Per-role generated-password length. ops is the break-glass account typed by
# hand at the KVM/console, so keep it short; dashboard/grafana are web logins
# (paste-friendly) and stay long. Roles not listed use the default.
ceph_password_length = { ops = 16 }
# (paste-friendly) and stay long. The metrics-worker RGW keys follow the
# AWS/RGW key shape (20-char access id, 40-char secret). Roles not listed use
# the default.
ceph_password_length = {
ops = 16
metrics_worker_access = 20
metrics_worker_secret = 40
}
ceph_password_default_length = 32
# Flatten (cluster, secret-role) -> { vault, title, length } across all
+5
View File
@@ -73,5 +73,10 @@ locals {
grafana = "${local.secret_prefix}_GRAFANA_PASSWORD"
s3_restic_access = "${local.secret_prefix}_S3_SVC_YUCCA_RESTIC_ACCESS_KEY"
s3_restic_secret = "${local.secret_prefix}_S3_SVC_YUCCA_RESTIC_SECRET_KEY"
# RGW admin (read-only) keys for the metrics worker. Titled <CLUSTER>_
# METRICS_WORKER_* (no _CEPH infix) to match the metrics-worker consumer's
# 1P contract, which is named by cluster, not by the ceph subsystem.
metrics_worker_access = "${upper(var.cluster_name)}_METRICS_WORKER_ACCESS_KEY"
metrics_worker_secret = "${upper(var.cluster_name)}_METRICS_WORKER_SECRET_KEY"
}
}
@@ -14,3 +14,5 @@ vault_ceph_dashboard_password: op://${vault}/${secrets.dashboard}/password
vault_grafana_admin_password: op://${vault}/${secrets.grafana}/password
vault_s3_restic_access_key: op://${vault}/${secrets.s3_restic_access}/password
vault_s3_restic_secret_key: op://${vault}/${secrets.s3_restic_secret}/password
vault_metrics_worker_access_key: op://${vault}/${secrets.metrics_worker_access}/password
vault_metrics_worker_secret_key: op://${vault}/${secrets.metrics_worker_secret}/password