mediamark: use ephemeral arrstack virtual keys
ci/woodpecker/pr/vector-test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful

The static sonarr/radarr API keys were copies of the real per-app keys,
seeded by hand into kv and never rotated. The arrstack secrets engine can
mint short-lived machine tokens instead, so mediamark leases one rather
than holding a copy of the real thing.

Drop the sonarr-apikey and radarr-apikey VaultStaticSecrets.
Add an arrstack-creds VaultAuth bound to the new `mediamark` k8s role.
Add an arrstack-virtual-key VaultDynamicSecret reading arrstack/creds/mediamark.
Project the leased token to both /etc/mediamark/keys/{sonarr,radarr}.
Point MEDIAMARK_{SONARR,RADARR}_URL at arrproxy-api, which is the only
thing that honours a virtual key.
Reload on arrstack-virtual-key instead of the removed secrets.
This commit is contained in:
2026-08-30 00:15:07 +10:00
parent 5ea193b957
commit fbe7348428
5 changed files with 54 additions and 49 deletions
+12 -11
View File
@@ -5,7 +5,7 @@ metadata:
name: mediamark
namespace: mediamark
annotations:
secret.reloader.stakater.com/reload: "sonarr-apikey,radarr-apikey"
secret.reloader.stakater.com/reload: "arrstack-virtual-key"
spec:
replicas: 2
selector:
@@ -45,10 +45,13 @@ spec:
value: /media
- name: MEDIAMARK_KEYS_DIR
value: /etc/mediamark/keys
# Virtual keys are only honoured by arrproxy, which validates the
# machine token and injects the real per-app key upstream; the
# sonarr/radarr Services would reject them.
- name: MEDIAMARK_SONARR_URL
value: http://sonarr-adult.arrstack.svc.cluster.local:8989/3aa168/sonarr
value: http://arrproxy-api.arrstack.svc.cluster.local:8080/3aa168/sonarr
- name: MEDIAMARK_RADARR_URL
value: http://radarr-adult.arrstack.svc.cluster.local:7878/3aa168/radarr
value: http://arrproxy-api.arrstack.svc.cluster.local:8080/3aa168/radarr
# oauth2-proxy --pass-user-headers forwards the Authentik groups as a
# comma-joined X-Forwarded-Groups; X-Auth-Request-Groups is
# auth_request-response-only and never reaches a proxied upstream.
@@ -95,19 +98,17 @@ spec:
- name: mediastore
persistentVolumeClaim:
claimName: mediamark-mediastore
# Per-app *arr API keys as one file per app under MEDIAMARK_KEYS_DIR,
# mirroring the arrproxy keys projection.
# One ephemeral virtual key covers both apps, so the same token lands on
# both per-app files under MEDIAMARK_KEYS_DIR; mediamark re-reads the
# file per request, so lease renewal rotates in place.
- name: arr-keys
projected:
sources:
- secret:
name: sonarr-apikey
name: arrstack-virtual-key
items:
- key: apitoken
- key: token
path: sonarr
- secret:
name: radarr-apikey
items:
- key: apitoken
- key: token
path: radarr
restartPolicy: Always
+1
View File
@@ -6,6 +6,7 @@ resources:
- namespace.yaml
- vaultauth.yaml
- vaultstaticsecret.yaml
- vaultdynamicsecret.yaml
- pv-mediastore.yaml
- pvc-mediastore.yaml
- deployment.yaml
+20
View File
@@ -16,3 +16,23 @@ spec:
method: kubernetes
mount: k8s/au/syd1
vaultConnectionRef: vso-system/default
---
# Separate auth for the arrstack secrets engine: the `mediamark` k8s role is the
# only one whose policy grants arrstack/creds/mediamark.
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
name: arrstack-creds
namespace: mediamark
spec:
allowedNamespaces:
- mediamark
kubernetes:
audiences:
- vault
role: mediamark
serviceAccount: default
tokenExpirationSeconds: 600
method: kubernetes
mount: k8s/au/syd1
vaultConnectionRef: vso-system/default
@@ -0,0 +1,21 @@
---
# Ephemeral arrstack virtual key. The engine mints one machine token covering
# both radarr and sonarr; it is only honoured by arrproxy, which validates it and
# swaps in the real per-app key upstream. Role ttl is 60s, so VSO renews the
# lease continuously (renewalPercent default 67) and rewrites the secret; the
# reloader annotation restarts pods when the token actually changes.
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
name: arrstack-virtual-key
namespace: mediamark
spec:
allowStaticCreds: false
destination:
create: true
name: arrstack-virtual-key
overwrite: true
mount: arrstack
path: creds/mediamark
revoke: true
vaultAuthRef: arrstack-creds
@@ -20,41 +20,3 @@ spec:
refreshAfter: 5m
type: kv-v2
vaultAuthRef: default
---
# Sonarr (adult tier) API key, projected into the mediamark keys dir as
# /etc/mediamark/keys/sonarr.
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: sonarr-apikey
namespace: mediamark
spec:
destination:
create: true
name: sonarr-apikey
overwrite: true
hmacSecretData: true
mount: kv
path: kubernetes/namespace/mediamark/default/sonarr
refreshAfter: 5m
type: kv-v2
vaultAuthRef: default
---
# Radarr (adult tier) API key, projected into the mediamark keys dir as
# /etc/mediamark/keys/radarr.
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: radarr-apikey
namespace: mediamark
spec:
destination:
create: true
name: radarr-apikey
overwrite: true
hmacSecretData: true
mount: kv
path: kubernetes/namespace/mediamark/default/radarr
refreshAfter: 5m
type: kv-v2
vaultAuthRef: default