mirror of
https://github.com/immich-app/yucca.git
synced 2026-09-30 13:33:00 +08:00
feat(ceph): add read-only metrics-worker RGW admin user + keys (#188)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user