Add k3s, 1Password Connect, and systemd nix-container-builder to ringtail #209
9 changed files with 173 additions and 23 deletions
Add 1Password Connect + External Secrets to ringtail k3s
Deploy the full ESO stack on ringtail, matching the indri pattern: - 4 ArgoCD apps (1password-connect, external-secrets-crds, external-secrets, external-secrets-config) targeting ringtail k3s cluster - ExternalSecret for forgejo-runner-amd64 token (replaces Ansible-managed secret) - Ansible playbook bootstraps 1Password Connect credentials instead of directly managing runner tokens Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
commit
0d3269e8d6
|
|
@ -4,10 +4,18 @@
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
pre_tasks:
|
pre_tasks:
|
||||||
- name: Fetch Forgejo runner registration token from 1Password
|
- name: Fetch 1Password Connect credentials from 1Password
|
||||||
ansible.builtin.command:
|
ansible.builtin.command:
|
||||||
cmd: op read "op://vg6xf6vvfmoh5hqjjhlhbeoaie/Forgejo Secrets/runner_reg"
|
cmd: op read "op://vg6xf6vvfmoh5hqjjhlhbeoaie/1Password Connect/credentials-file"
|
||||||
register: _runner_token
|
register: _op_credentials
|
||||||
|
changed_when: false
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
|
||||||
|
- name: Fetch 1Password Connect token from 1Password
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: op read "op://vg6xf6vvfmoh5hqjjhlhbeoaie/1Password Connect/token"
|
||||||
|
register: _op_token
|
||||||
changed_when: false
|
changed_when: false
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
become: false
|
become: false
|
||||||
|
|
@ -56,36 +64,32 @@
|
||||||
delay: 5
|
delay: 5
|
||||||
until: _k3s_ready.rc == 0
|
until: _k3s_ready.rc == 0
|
||||||
|
|
||||||
- name: Create forgejo-runner namespace
|
- name: Create 1password namespace
|
||||||
ansible.builtin.command: k3s kubectl create namespace forgejo-runner
|
ansible.builtin.command: k3s kubectl create namespace 1password
|
||||||
register: _ns
|
register: _ns
|
||||||
changed_when: _ns.rc == 0
|
changed_when: _ns.rc == 0
|
||||||
failed_when: _ns.rc != 0 and 'AlreadyExists' not in _ns.stderr
|
failed_when: _ns.rc != 0 and 'AlreadyExists' not in _ns.stderr
|
||||||
|
|
||||||
- name: Check if forgejo-runner-env secret exists
|
- name: Create or update op-credentials secret
|
||||||
ansible.builtin.command: k3s kubectl get secret forgejo-runner-env -n forgejo-runner
|
|
||||||
register: _secret_exists
|
|
||||||
changed_when: false
|
|
||||||
failed_when: false
|
|
||||||
|
|
||||||
- name: Create forgejo-runner-env secret
|
|
||||||
ansible.builtin.command: >
|
|
||||||
k3s kubectl create secret generic forgejo-runner-env
|
|
||||||
--namespace=forgejo-runner
|
|
||||||
--from-literal=RUNNER_TOKEN={{ _runner_token.stdout }}
|
|
||||||
changed_when: true
|
|
||||||
when: _secret_exists.rc != 0
|
|
||||||
no_log: true
|
|
||||||
|
|
||||||
- name: Update forgejo-runner-env secret
|
|
||||||
ansible.builtin.shell:
|
ansible.builtin.shell:
|
||||||
cmd: |
|
cmd: |
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
k3s kubectl create secret generic forgejo-runner-env \
|
k3s kubectl create secret generic op-credentials \
|
||||||
--namespace=forgejo-runner \
|
--namespace=1password \
|
||||||
--from-literal=RUNNER_TOKEN={{ _runner_token.stdout }} \
|
--from-literal=1password-credentials.json='{{ _op_credentials.stdout }}' \
|
||||||
|
--dry-run=client -o yaml | k3s kubectl apply -f -
|
||||||
|
executable: /bin/bash
|
||||||
|
changed_when: true
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Create or update onepassword-token secret
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: |
|
||||||
|
set -o pipefail
|
||||||
|
k3s kubectl create secret generic onepassword-token \
|
||||||
|
--namespace=1password \
|
||||||
|
--from-literal=token={{ _op_token.stdout }} \
|
||||||
--dry-run=client -o yaml | k3s kubectl apply -f -
|
--dry-run=client -o yaml | k3s kubectl apply -f -
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
when: _secret_exists.rc == 0
|
|
||||||
changed_when: true
|
changed_when: true
|
||||||
no_log: true
|
no_log: true
|
||||||
|
|
|
||||||
32
argocd/apps/1password-connect-ringtail.yaml
Normal file
32
argocd/apps/1password-connect-ringtail.yaml
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# 1Password Connect for ringtail k3s cluster
|
||||||
|
# Same chart/values as indri, different destination
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# 1. Bootstrap secrets via ansible (provision-ringtail creates 1password namespace,
|
||||||
|
# op-credentials and onepassword-token secrets)
|
||||||
|
# 2. Sync BEFORE external-secrets-ringtail
|
||||||
|
#
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: 1password-connect-ringtail
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
sources:
|
||||||
|
- repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/connect-helm-charts.git
|
||||||
|
targetRevision: connect-2.3.0
|
||||||
|
path: charts/connect
|
||||||
|
helm:
|
||||||
|
releaseName: onepassword-connect
|
||||||
|
valueFiles:
|
||||||
|
- $values/argocd/manifests/1password-connect/values.yaml
|
||||||
|
- repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://ringtail.tail8d86e.ts.net:6443
|
||||||
|
namespace: 1password
|
||||||
|
syncPolicy:
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
24
argocd/apps/external-secrets-config-ringtail.yaml
Normal file
24
argocd/apps/external-secrets-config-ringtail.yaml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# External Secrets Configuration for ringtail k3s cluster
|
||||||
|
# Same ClusterSecretStore manifests as indri, different destination
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# - 1password-connect-ringtail is deployed and healthy
|
||||||
|
# - external-secrets-ringtail operator is deployed and CRDs are installed
|
||||||
|
#
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: external-secrets-config-ringtail
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git
|
||||||
|
targetRevision: main
|
||||||
|
path: argocd/manifests/external-secrets
|
||||||
|
destination:
|
||||||
|
server: https://ringtail.tail8d86e.ts.net:6443
|
||||||
|
namespace: external-secrets
|
||||||
|
syncPolicy:
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
24
argocd/apps/external-secrets-crds-ringtail.yaml
Normal file
24
argocd/apps/external-secrets-crds-ringtail.yaml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# External Secrets Operator CRDs for ringtail k3s cluster
|
||||||
|
# Same CRDs source as indri, different destination
|
||||||
|
#
|
||||||
|
# Must be synced BEFORE external-secrets-ringtail operator app.
|
||||||
|
#
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: external-secrets-crds-ringtail
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/external-secrets.git
|
||||||
|
targetRevision: helm-chart-2.0.0
|
||||||
|
path: config/crds/bases
|
||||||
|
directory:
|
||||||
|
exclude: 'kustomization.yaml'
|
||||||
|
destination:
|
||||||
|
server: https://ringtail.tail8d86e.ts.net:6443
|
||||||
|
syncPolicy:
|
||||||
|
syncOptions:
|
||||||
|
- ServerSideApply=true
|
||||||
|
- CreateNamespace=false
|
||||||
32
argocd/apps/external-secrets-ringtail.yaml
Normal file
32
argocd/apps/external-secrets-ringtail.yaml
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# External Secrets Operator for ringtail k3s cluster
|
||||||
|
# Same chart/values as indri, different destination
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# - 1password-connect-ringtail must be deployed and healthy
|
||||||
|
# - external-secrets-crds-ringtail must be synced first
|
||||||
|
#
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: external-secrets-ringtail
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
sources:
|
||||||
|
- repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/external-secrets.git
|
||||||
|
targetRevision: helm-chart-2.0.0
|
||||||
|
path: deploy/charts/external-secrets
|
||||||
|
helm:
|
||||||
|
releaseName: external-secrets
|
||||||
|
valueFiles:
|
||||||
|
- $values/argocd/manifests/external-secrets/values.yaml
|
||||||
|
- repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://ringtail.tail8d86e.ts.net:6443
|
||||||
|
namespace: external-secrets
|
||||||
|
syncPolicy:
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
27
argocd/manifests/forgejo-runner-amd64/external-secret.yaml
Normal file
27
argocd/manifests/forgejo-runner-amd64/external-secret.yaml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# ExternalSecret for Forgejo Runner token (amd64)
|
||||||
|
#
|
||||||
|
# 1Password item: "Forgejo Secrets" in blumeops vault
|
||||||
|
# Field: runner_reg (runner registration token)
|
||||||
|
#
|
||||||
|
# Non-secret env vars (FORGEJO_URL, RUNNER_NAME, RUNNER_LABELS) live in the
|
||||||
|
# deployment spec so that changes (e.g. image version bumps) trigger a rollout
|
||||||
|
# automatically.
|
||||||
|
#
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: forgejo-runner-env
|
||||||
|
namespace: forgejo-runner
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: onepassword-blumeops
|
||||||
|
target:
|
||||||
|
name: forgejo-runner-env
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
- secretKey: RUNNER_TOKEN
|
||||||
|
remoteRef:
|
||||||
|
key: Forgejo Secrets
|
||||||
|
property: runner_reg
|
||||||
|
|
@ -4,3 +4,4 @@ resources:
|
||||||
- namespace.yaml
|
- namespace.yaml
|
||||||
- configmap.yaml
|
- configmap.yaml
|
||||||
- deployment.yaml
|
- deployment.yaml
|
||||||
|
- external-secret.yaml
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
K3s cluster on ringtail with Forgejo Actions runner (`k8s-amd64` label) for native amd64 container builds, managed via ArgoCD multi-cluster.
|
K3s cluster on ringtail with Forgejo Actions runner (`k8s-amd64` label) for native amd64 container builds, managed via ArgoCD multi-cluster. Includes 1Password Connect + External Secrets Operator for automated secret management, matching the indri pattern.
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,12 @@ Ringtail runs a single-node k3s cluster for native amd64 workloads, registered i
|
||||||
- **Token:** `/etc/k3s/token` (generated on first provision)
|
- **Token:** `/etc/k3s/token` (generated on first provision)
|
||||||
- **Kubeconfig:** `/etc/rancher/k3s/k3s.yaml` (world-readable via `--write-kubeconfig-mode=644`)
|
- **Kubeconfig:** `/etc/rancher/k3s/k3s.yaml` (world-readable via `--write-kubeconfig-mode=644`)
|
||||||
|
|
||||||
|
### Secrets Management
|
||||||
|
|
||||||
|
1Password Connect + External Secrets Operator syncs secrets from 1Password to k8s, matching the [[1password|indri pattern]]. Bootstrap credentials (`op-credentials`, `onepassword-token`) are provisioned by Ansible; ArgoCD manages the operator stack.
|
||||||
|
|
||||||
|
Sync order: `1password-connect-ringtail` -> `external-secrets-crds-ringtail` -> `external-secrets-ringtail` -> `external-secrets-config-ringtail`
|
||||||
|
|
||||||
### Workloads
|
### Workloads
|
||||||
|
|
||||||
| Workload | Namespace | Label |
|
| Workload | Namespace | Label |
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue