Plataforma maceosoft — GitHub¶
Cómo se conecta la org GitHub maceosoft con el clúster HomeLab:
- Argo CD despliega desde el repo privado maceosoft/gitops.
- ARC (Actions Runner Controller) corre un runner self-hosted de GitHub Actions dentro del clúster
(un scale set por organización: arc-runners para maceosoft y arc-runners-symintel para la org antigua; ver
Dos organizaciones).
- OpenTofu gestiona la org desde un pipeline que corre en uno de esos
runners, y guarda su estado en el clúster.
Dónde se ejecuta en la guía de implementación
- Pasos 1 y 2 (manuales): Fase 0 — GitHub y 1Password
- Paso 3 (secretos de plataforma): Fase 4 — 4.2, antes del ApplicationSet de bootstrap
- Pasos 4 y 5 (ARC y pipeline): Fase 4 — 4.11
Esta página es la referencia completa: permisos, campos, verificación y rotación.
Repos involucrados
| Repo | Qué contiene |
|---|---|
maceosoft/homelab |
Este sitio. Ansible: k3s, Argo CD y los secretos de plataforma (1Password → clúster) |
maceosoft/gitops |
Applications de Argo CD, incluidos ARC y el runner de OpenTofu |
maceosoft/core-pipelines |
Workflows reutilizables (tofu.yml, CI, deploy FTP) |
maceosoft/infra |
OpenTofu: repos, environments y secrets de la org |
Cómo encaja¶
flowchart LR
OP[1Password<br/>bóveda HomeLab] -->|playbook-platform-secrets.yml| K8S
subgraph K8S[Clúster k3s]
ARGO[ArgoCD] -->|App maceosoft-argocd| GITOPS[(maceosoft/gitops)]
ARGO --> ARC[ARC controller]
ARC --> RT[arc-runners]
RT --> STATE[(ns terraform<br/>Secret tfstate-default-github)]
end
INFRA[maceosoft/infra] -->|tofu.yml de core-pipelines| RT
RT -->|App maceosoft-terraform| GH[org maceosoft]
Hay piezas que tienen que existir antes de que Argo CD o el pipeline puedan funcionar. Esas se crean a mano, una sola vez, y OpenTofu no las gestiona ni las importa:
| Qué | Por qué a mano |
|---|---|
Repos gitops, infra, core-pipelines |
Sin ellos no hay de dónde desplegar ni pipeline que corra OpenTofu |
App maceosoft-argocd |
Argo CD la necesita para leer el repo privado que despliega todo lo demás |
| GitHub Apps y OAuth App | GitHub no permite crear OAuth Apps por API, y las GitHub Apps piden confirmación en el navegador |
Todo lo demás (el repo api y los repos futuros) lo crea el pipeline de
infra.
Items en 1Password¶
Todos en la bóveda HomeLab. Los scripts los leen a través de la app de
escritorio de 1Password, que tiene que estar desbloqueada y con Settings →
Developer → Integrate with other apps activado. Para indicar qué cuenta
usar se define ONEPASSWORD_ACCOUNT_NAME con el nombre de tu cuenta tal
como aparece arriba a la izquierda en la barra lateral de la app (por
ejemplo Mi Cuenta; si no la defines, usa Personal):
| Item | Tipo de item | Campos | Lo usa |
|---|---|---|---|
maceosoft-terraform |
Nota segura | app_id, installation_id, private_key |
Runner de OpenTofu (TF_VAR_github_app_*) |
maceosoft-arc-runners |
Nota segura | app_id, installation_id, private_key |
ARC (registro del runner) |
maceosoft-argocd |
Nota segura | app_id, installation_id, private_key |
Argo CD lee maceosoft/gitops (argocd/repo-gitops) |
symintel-arc-runners (opcional) |
Nota segura | app_id, installation_id, private_key |
ARC de la org antigua (symintel): registro de su scale set. Ver Dos organizaciones |
symintel-terraform (opcional) |
Nota segura | app_id, installation_id, private_key |
OpenTofu de la org antigua; sin él, esos runners no tienen credenciales de OpenTofu |
sealed-secrets |
Nota segura | certificate, private_key (opcional hasta la Fase 6) |
Llave de cifrado de Sealed Secrets: sobrevive si reinstalas K3s |
maceosoft-dex |
Nota segura | GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET (+ VCLUSTER_CLIENT_SECRET, que genera el playbook) |
Dex (login con GitHub) |
discord-webhooks |
Nota segura | critical, warnings: URL de un webhook de Discord por canal; deployments (opcional): el del canal despliegues para las notificaciones de Argo CD (opcional: monitoreo) |
Alertmanager envía las alertas (4.13). Cómo crearlos: Discord y healthchecks.io |
healthchecks-ping |
Nota segura | url: ping URL del check de healthchecks.io (opcional: monitoreo) |
Alertmanager le manda un ping cada 5 minutos para avisar que el monitoreo sigue vivo. Cómo crearla: Discord y healthchecks.io |
grafana-admin |
Nota segura | password y, si quieres, username (por defecto admin) (opcional: monitoreo) |
Administrador de Grafana |
ftp-<repo> |
Nota segura | dev_host, dev_user, dev_password, dev_remote_dir, prod_host, prod_user, prod_password, prod_remote_dir |
OpenTofu → secrets FTP de <repo> (TF_VAR_ftp) |
Cómo crear un item con campos propios¶
El playbook busca cada valor por su ruta op://HomeLab/<item>/<campo>, así
que el título del item y el nombre de cada campo tienen que ser exactos
(minúsculas, con guion bajo).
- En 1Password abre la bóveda
HomeLab→ Nuevo elemento → Nota segura (Secure Note). - En Título escribe el nombre del item, por ejemplo
maceosoft-terraform. - Por cada campo: + Añadir más → elige el tipo (Texto o
Contraseña) → en la etiqueta del campo escribe el nombre exacto
(por ejemplo
app_id) → pega el valor. - Agrega los campos directamente en el item. No crees una sección para agruparlos: con sección la ruta cambia y el playbook no los encuentra.
- Guarda.
Usa Contraseña para los valores secretos (se ocultan) y Texto para el resto. Cada tabla de abajo dice qué tipo lleva cada campo.
También puedes crear el item con la CLI de 1Password (op), con 1Password desbloqueado. Cada campo se escribe como
nombre[tipo]=valor, donde el tipo es password (valor secreto) o text; op crea los campos sueltos, sin sección.
Los valores secretos no se escriben en el comando: se pegan sin eco con read -rs:
# pega la contraseña y Enter (no se ve)
read -rs FTP_DEV_PASS
op item create --category "Secure Note" --vault HomeLab --title ftp-mi-repo \
"dev_host[text]=ftp.ejemplo.com" "dev_user[text]=usuario" "dev_password[password]=$FTP_DEV_PASS"
unset FTP_DEV_PASS
Si tienes más de una cuenta de 1Password, exporta antes OP_ACCOUNT con la tuya. Para un valor aleatorio usa
$(openssl rand -hex 32). Los items de la IA local (tokens del router, Open Terminal…) ya tienen sus comandos en
Gestión de secretos.
Paso 1 — GitHub Apps y OAuth App (manual)¶
Hazlo con una cuenta owner de la organización maceosoft.
maceosoft-terraform¶
maceosoft → Settings → Developer settings → GitHub Apps → New GitHub App
| Campo | Valor |
|---|---|
| GitHub App name | maceosoft-terraform |
| Homepage URL | https://github.com/maceosoft |
| Webhook → Active | desmarcado |
| Where can this GitHub App be installed? | Only on this account |
El resto del formulario (Callback URL, Setup URL, Request user authorization, eventos) se deja vacío o sin marcar.
| Repository permission | Acceso | Para qué |
|---|---|---|
| Actions | Read and write | Gestión de Actions en los repos |
| Administration | Read and write | Crear repos y branch protection |
| Contents | Read and write | Archivos del repo |
| Environments | Read and write | Environments dev / prod |
| Metadata | Read-only | Obligatorio |
| Secrets | Read and write | Secrets FTP por environment |
| Variables | Read and write | PROJECT_STACK, FTP_PROTOCOL |
| Workflows | Read and write | Archivos .github/workflows/* |
| Organization permission | Acceso | Para qué |
|---|---|---|
| Administration | Read and write | Crear repos en la org |
Todos los demás permisos quedan en No access.
Después de Create GitHub App, junta tres datos y guárdalos en el item
maceosoft-terraform de 1Password (Nota segura, ver
cómo crearlo):
| Campo en 1Password | Tipo | Dato | Dónde está en GitHub |
|---|---|---|---|
app_id |
Texto | App ID | Página de la App, pestaña General: línea App ID (un número, por ejemplo 1234567) |
private_key |
Contraseña | Private key | Misma página, abajo en Private keys → Generate a private key. Se descarga un archivo maceosoft-terraform.<fecha>.private-key.pem. Ábrelo con un editor de texto y copia todo, incluidas las líneas -----BEGIN RSA PRIVATE KEY----- y -----END RSA PRIVATE KEY----- |
installation_id |
Texto | Installation ID | Menú izquierdo de la App → Install App → Install junto a maceosoft → All repositories → Install. GitHub te lleva a https://github.com/organizations/maceosoft/settings/installations/<número>: ese número final |
Así queda el item:
maceosoft-terraform (Nota segura · bóveda HomeLab)
├── app_id 1234567
├── installation_id 87654321
└── private_key •••••••• (el .pem completo)
Se hacen solo desde la web: crear la App, generar su llave privada (Generate a private key) y instalarla. GitHub no ofrece CLI ni API para eso (la creación de Apps por manifiesto también exige confirmar en el navegador). Guardar los datos en 1Password lo puedes hacer de las dos formas:
Al pegar el .pem en un campo Contraseña se pierden los saltos de línea. No
importa: el playbook reconstruye la llave. Cuando el item esté guardado,
borra el .pem de Descargas.
Lo que sí se automatiza es leer los dos números y guardar el item.
-
Lista las Apps instaladas en la org y saca
App IDeInstallation ID(necesita el permiso de organización:gh auth refresh -s admin:read:orguna sola vez): -
Con el
.pemdescargado, crea el item (1Password desbloqueado; si tienes más de una cuenta de 1Password, exportaOP_ACCOUNTantes). El valor del.pemse lee del archivo y nunca se escribe en el comando:APP=maceosoft-terraform read -r APP_ID INST_ID < <(gh api orgs/maceosoft/installations \ --jq ".installations[] | select(.app_slug==\"$APP\") | \"\(.app_id) \(.id)\"") op item create --category "Secure Note" --vault HomeLab --title "$APP" \ "app_id[text]=$APP_ID" "installation_id[text]=$INST_ID" \ "private_key[password]=$(cat ~/Downloads/$APP.*.private-key.pem)" -
Verifica sin mostrar valores y borra el
.pem:
El mismo comando sirve para las demás Apps: solo cambia APP (maceosoft-arc-runners, maceosoft-argocd, y
symintel-arc-runners / symintel-terraform si usas la org antigua, cambiando orgs/maceosoft por orgs/symintel).
maceosoft-arc-runners¶
Es la App con la que ARC registra el runner arc-runners en la org. Se
crea en el mismo formulario que maceosoft-terraform, pero es otra App:
nombre, permisos y credenciales propios.
maceosoft → Settings → Developer settings → GitHub Apps → New GitHub App
| Campo | Valor |
|---|---|
| GitHub App name | maceosoft-arc-runners |
| Homepage URL | https://github.com/maceosoft |
| Webhook → Active | desmarcado |
| Where can this GitHub App be installed? | Only on this account |
El resto del formulario (Callback URL, Setup URL, Request user authorization, eventos) se deja vacío o sin marcar.
| Repository permission | Acceso | Para qué |
|---|---|---|
| Actions | Read-only | Ver los jobs en cola que tiene que tomar el runner |
| Administration | Read and write | Registrar runners (lo pide ARC) |
| Metadata | Read-only | Obligatorio |
| Organization permission | Acceso | Para qué |
|---|---|---|
| Self-hosted runners | Read and write | Registrar y borrar el runner arc-runners en la org |
Todos los demás permisos quedan en No access.
Después de Create GitHub App, guarda sus tres datos en el item
maceosoft-arc-runners de 1Password (Nota segura, ver
cómo crearlo):
| Campo en 1Password | Tipo | Dato | Dónde está en GitHub |
|---|---|---|---|
app_id |
Texto | App ID | Página de la App, pestaña General: línea App ID |
private_key |
Contraseña | Private key | Misma página, abajo en Private keys → Generate a private key. Se descarga maceosoft-arc-runners.<fecha>.private-key.pem. Ábrelo con un editor de texto y copia todo, incluidas las líneas -----BEGIN RSA PRIVATE KEY----- y -----END RSA PRIVATE KEY----- |
installation_id |
Texto | Installation ID | Menú izquierdo de la App → Install App → Install junto a maceosoft → All repositories → Install. El número al final de la URL https://github.com/organizations/maceosoft/settings/installations/<número> |
Así queda el item:
maceosoft-arc-runners (Nota segura · bóveda HomeLab)
├── app_id 2345678
├── installation_id 98765432
└── private_key •••••••• (el .pem completo)
Crear la App, su llave e instalarla es solo desde la web; guardar el item lo puedes hacer de las dos formas:
Los tres valores son distintos de los de maceosoft-terraform: cada App
tiene su App ID, su llave y su instalación. No copies los de la otra. Cuando
el item esté guardado, borra el .pem de Descargas.
El mismo comando de maceosoft-terraform con APP=maceosoft-arc-runners: gh api saca los
números de esta App, así que no se mezclan con los de la otra.
APP=maceosoft-arc-runners
read -r APP_ID INST_ID < <(gh api orgs/maceosoft/installations \
--jq ".installations[] | select(.app_slug==\"$APP\") | \"\(.app_id) \(.id)\"")
op item create --category "Secure Note" --vault HomeLab --title "$APP" \
"app_id[text]=$APP_ID" "installation_id[text]=$INST_ID" \
"private_key[password]=$(cat ~/Downloads/$APP.*.private-key.pem)"
python3 ansible/scripts/apply_platform_secrets.py --check
# en macOS: rm -P
shred -u ~/Downloads/$APP.*.private-key.pem
OAuth App Maceosoft Dex¶
maceosoft → Settings → Developer settings → OAuth Apps → New OAuth App
| Campo | Valor |
|---|---|
| Application name | Maceosoft Dex |
| Homepage URL | https://argocd.homelab.local |
| Redirect URIs | https://argocd.homelab.local/api/dex/callback (solo esta) |
Después de Register application, crea el item maceosoft-dex en la
bóveda HomeLab (Nota segura, ver cómo crearlo)
con estos dos campos:
| Campo en 1Password | Tipo | Dato | Dónde está en GitHub |
|---|---|---|---|
GITHUB_CLIENT_ID |
Texto | Client ID | Página de la OAuth App: línea Client ID |
GITHUB_CLIENT_SECRET |
Contraseña | Client secret | Misma página → Generate a new client secret. GitHub lo muestra una sola vez: cópialo en ese momento |
Así queda el item (el último campo lo agrega solo
playbook-dex-oauth-secrets.yml la primera vez que corre: es el secreto
del cliente vCluster de Dex, no viene de GitHub):
maceosoft-dex (Nota segura · bóveda HomeLab)
├── GITHUB_CLIENT_ID Ov23li…
├── GITHUB_CLIENT_SECRET ••••••••
└── VCLUSTER_CLIENT_SECRET •••••••• (lo genera el playbook)
Crear la OAuth App y generar su client secret se hace solo desde la web: GitHub no tiene API para OAuth Apps. Guardar los dos valores en 1Password lo puedes hacer de las dos formas:
Crea la Nota segura maceosoft-dex y pega cada valor de la tabla en su campo
(cómo crearlo).
Una vez que tienes los dos valores, guárdalos sin que se vean en pantalla (si tienes más de una cuenta de 1Password,
exporta OP_ACCOUNT antes):
Para comprobar que alguien está en el team devops (o agregarlo) desde la consola:
gh api orgs/maceosoft/teams/devops/memberships/<usuario> (devuelve "state": "active") y, para sumarlo como miembro,
gh api -X PUT orgs/maceosoft/teams/devops/memberships/<usuario> -f role=member.
Solo puede entrar el team devops de maceosoft, y sus miembros quedan
como admin de Argo CD. Se aplica en el
paso 4.7 de la Fase 4.
Paso 2 — Repos, App de Argo CD y FTP (manual)¶
-
Repos (privados), creados en
maceosofty con su contenido subido con git:gitops.core-pipelines: después hay que dejarlo accesible para los demás repos de la org (abajo). Mientras pruebas, los demás repos lo usan con@main; el tagv1se crea cuando todo funcione (ver el README decore-pipelines).infra.
Crea cada repo en la org con New repository (privado) y sube su contenido con git. Después, en
core-pipelines: Settings → Actions → General → Access, elige "Accessible from repositories in the 'maceosoft' organization".Con la CLI de GitHub, desde la carpeta de cada proyecto:
gh repo create maceosoft/gitops --private --source . --remote origin --push # igual para core-pipelines e infra gh repo list maceosoft --json name,visibility --jq '.[] | [.name, .visibility] | @tsv' # core-pipelines accesible desde los demás repos de la org gh api -X PUT repos/maceosoft/core-pipelines/actions/permissions/access -f access_level=organization- GitHub App
maceosoft-argocd, con la que Argo CD lee el repo privadogitops. Va después de los repos porque se instala solo engitops. (Las deploy keys están deshabilitadas en la organización, por eso se usa una App.)
maceosoft → Settings → Developer settings → GitHub Apps → New GitHub App
Campo Valor GitHub App name maceosoft-argocdHomepage URL https://github.com/maceosoftWebhook → Active desmarcado Where can this GitHub App be installed? Only on this account El resto del formulario se deja vacío o sin marcar.
Repository permission Acceso Para qué Contents Read-only Clonar el repo Metadata Read-only Obligatorio Sin permisos de organización. Todos los demás quedan en No access.
Después de Create GitHub App, guarda sus tres datos en el item
maceosoft-argocdde 1Password (Nota segura, ver cómo crearlo):Campo en 1Password Tipo Dato Dónde está en GitHub app_idTexto App ID Página de la App, pestaña General: línea App ID private_keyContraseña Private key Misma página, abajo en Private keys → Generate a private key. Copia todo el .pemdescargado, incluidas las líneasBEGIN/ENDinstallation_idTexto Installation ID Menú izquierdo → Install App → Install junto a maceosoft→ Only select repositories → eligegitops→ Install. El número al final de la URL…/settings/installations/<número>Instálala solo en
gitops: con esa llave se puede leer el código de todos los repos donde esté instalada. Borra el.pemal terminar.Crear la App, su llave e instalarla es solo desde la web; guardar el item lo puedes hacer de las dos formas:
Crea la Nota segura
maceosoft-argocdy pega cada dato de la tabla en su campo (cómo crearlo).El mismo comando de
maceosoft-terraform, conAPP=maceosoft-argocd:APP=maceosoft-argocd read -r APP_ID INST_ID < <(gh api orgs/maceosoft/installations \ --jq ".installations[] | select(.app_slug==\"$APP\") | \"\(.app_id) \(.id)\"") op item create --category "Secure Note" --vault HomeLab --title "$APP" \ "app_id[text]=$APP_ID" "installation_id[text]=$INST_ID" \ "private_key[password]=$(cat ~/Downloads/$APP.*.private-key.pem)" # en macOS: rm -P shred -u ~/Downloads/$APP.*.private-key.pem -
Credenciales FTP (File Transfer Protocol) del repo
api, el primer proyecto del mapa condeploy = true: títuloftp-api, tipo Nota segura. Para cada repo que agregues después, sigue el procedimiento — Agregar un repo. Campos, creado igual que los otros:Campo Tipo Ejemplo dev_hostTexto dev.tu-cpanel.example.comdev_userTexto usuario_devdev_passwordContraseña dev_remote_dirTexto /home/usuario/dev.maceosoft.example.comprod_hostTexto tu-cpanel.example.comprod_userTexto usuario_prodprod_passwordContraseña prod_remote_dirTexto /home/usuario/public_htmlCambia los hosts, usuarios y carpetas por los tuyos; las dos contraseñas se pegan sin eco (si tienes más de una cuenta de 1Password, exporta
OP_ACCOUNTantes):# pega cada contraseña y Enter read -rs FTP_DEV_PASS; read -rs FTP_PROD_PASS op item create --category "Secure Note" --vault HomeLab --title ftp-api \ "dev_host[text]=dev.tu-cpanel.example.com" "dev_user[text]=usuario_dev" \ "dev_password[password]=$FTP_DEV_PASS" "dev_remote_dir[text]=/home/usuario/dev.maceosoft.example.com" \ "prod_host[text]=tu-cpanel.example.com" "prod_user[text]=usuario_prod" \ "prod_password[password]=$FTP_PROD_PASS" "prod_remote_dir[text]=/home/usuario/public_html" unset FTP_DEV_PASS FTP_PROD_PASS -
Llave de Sealed Secrets (opcional: hace falta cuando empieces a guardar
SealedSecreten Git, p. ej. en la Fase 6). Sealed Secrets cifra los secretos con un par de llaves que, por defecto, el controlador genera dentro del clúster: si reinstalas K3s se pierde, y losSealedSecretque ya estaban en Git dejan de poder descifrarse. Por eso se genera una sola vez, se guarda en 1Password, y el playbook de secretos la lleva al clúster antes de que el controlador arranque.Genera el par en una carpeta temporal (
opensslviene en macOS y Linux):cd "$(mktemp -d)" openssl req -x509 -days 3650 -nodes -newkey rsa:4096 \ -keyout tls.key -out tls.crt -subj "/CN=sealed-secret/O=sealed-secret"Crea en 1Password el item
sealed-secrets(Nota segura, creado igual que los otros):Campo Tipo Valor certificateTexto El contenido completo de tls.crt(la llave pública), con las líneas-----BEGIN CERTIFICATE-----y-----END CERTIFICATE-----private_keyContraseña El contenido completo de tls.key(la llave privada), con sus líneasBEGIN/ENDPara copiar un archivo:
pbcopy < tls.crt(macOS) o ábrelo con un editor y copia todo.Con la CLI de 1Password los archivos se leen directamente (si tienes más de una cuenta de 1Password, exporta
OP_ACCOUNTantes):Cuando el item esté guardado, borra los archivos:
El certificado vale 10 años. El playbook comprueba que el certificado y la llave sean un par (si copiaste archivos de pares distintos, se detiene con un mensaje claro) y crea el Secret
kube-system/sealed-secrets-key-homelab, que el controlador detecta por su etiquetasealedsecrets.bitnami.com/sealed-secrets-key: active. Mientras el item no exista, el playbook avisa y sigue: Sealed Secrets generaría su propia llave.
Paso 3 — Clúster y secretos de plataforma¶
Con k3s instalado (Fase 3, Argo CD incluido):
# tu cuenta y tu bóveda
export ONEPASSWORD_ACCOUNT_NAME="Mi Cuenta"
export ONEPASSWORD_VAULT="HomeLab"
cd ansible
ansible-playbook -i inventory.ini playbook-platform-secrets.yml
playbook-platform-secrets.yml
crea los namespaces argocd, arc-runners (PSS privileged, por el sidecar dind) y terraform
(solo guarda el state de OpenTofu), y estos Secrets:
| Secret | Namespace | Contenido |
|---|---|---|
repo-gitops |
argocd |
App maceosoft-argocd: Argo CD puede clonar https://github.com/maceosoft/gitops.git |
arc-runners-github-app |
arc-runners |
App de ARC |
terraform-app |
arc-runners |
TF_VAR_github_app_id, TF_VAR_github_app_installation_id, TF_VAR_github_app_private_key |
tofu-vars |
arc-runners |
TF_VAR_ftp (todos los items ftp-<repo>) |
arc-runners-github-app, terraform-app |
arc-runners-symintel |
Lo mismo para la org antigua, desde symintel-arc-runners y symintel-terraform (solo si existen). El namespace se crea con PSS baseline |
sealed-secrets-key-homelab |
kube-system |
Par de llaves de Sealed Secrets (item sealed-secrets, si existe) |
discord-webhooks, healthchecks-ping, grafana-admin |
monitoring |
Webhooks de Discord, ping URL de healthchecks.io y contraseña de Grafana (los items del mismo nombre; solo si existen los tres). El namespace se crea con PSS privileged, porque node-exporter usa el disco y la red del nodo |
Un solo runner
Es un HomeLab: el único scale set (arc-runners, grupo Default) corre CI (integración continua),
deploys y OpenTofu, y tiene las credenciales de OpenTofu como variables de
entorno. Cualquier repo de maceosoft que corra un job ahí puede
alcanzarlas. Mantén la org solo con repos tuyos.
Siempre contra el HomeLab
El playbook usa ~/.kube/homelab-k3s.yaml (el que deja
k3s_fetch_kubeconfig), no el contexto actual de kubectl. Así no
escribe secretos en otro clúster. Para otro kubeconfig:
-e platform_kubeconfig=/ruta.
Es idempotente: vuelve a correrlo cada vez que rotes algo en 1Password o agregues
un item ftp-<repo>.
Dos organizaciones: un scale set por org¶
Un scale set de ARC se registra en una sola organización de GitHub (githubConfigUrl). Para que los mismos runners
atiendan a la org nueva (maceosoft) y a la antigua (symintel) hay dos scale sets, con un solo controller
(arc-controller) que atiende a los dos:
Org maceosoft |
Org symintel (antigua) |
|
|---|---|---|
| Application | arc-runners |
arc-runners-symintel |
| Namespace | arc-runners |
arc-runners-symintel |
| App de ARC (item de 1Password) | maceosoft-arc-runners |
symintel-arc-runners |
Nombre en runs-on: |
arc-runners |
arc-runners (el mismo) |
Caché /cache (RWX, Longhorn) |
20 GiB | 10 GiB, propia |
Docker (dind) |
Sí, con un sidecar privilegiado | Sí, igual |
| OpenTofu y FTP | Sí (terraform-app, tofu-vars) |
Solo si existe el item symintel-terraform |
Los dos usan la misma plantilla de runner
(values-scaleset.yaml); la org antigua cambia
githubConfigUrl (values-scaleset-symintel.yaml).
Cada namespace tiene sus propios Secrets, con el mismo nombre, así que los de una org no los ve la otra, y la caché tampoco se
comparte (una caché envenenada en una org no llega a la otra).
Para activar la org antigua: crea en symintel la App de ARC (igual que maceosoft-arc-runners, pero en esa
org) y guárdala en el item symintel-arc-runners; después corre playbook-platform-secrets.yml. Si el item no existe, el script no
crea el namespace ni el Secret y el scale set de la org antigua no arranca. Para quitarla, borra la Application
arc-runners-symintel y los items.
Paso 4 — GitOps¶
Argo CD sincroniza, entre otras, estas Applications:
| Application | Qué despliega |
|---|---|
arc-controller |
Controller de ARC (arc-systems) |
terraform-rbac |
ServiceAccount tofu-runner + Role (solo Secrets/Leases del namespace terraform) |
arc-runners |
El runner (hasta 3 en paralelo), con los Secrets del namespace como variables de entorno |
Paso 5 — Primer pipeline de OpenTofu¶
Haz un push a main de infra, o lánzalo desde Actions → tofu →
Run workflow (con la CLI: gh workflow run tofu.yml --repo maceosoft/infra --ref main y gh run watch --repo maceosoft/infra). El workflow
tofu.yml
corre en arc-runners: hace plan en los PRs (pull requests) y apply en main. En la
primera ejecución crea api.
Verificar¶
Antes del clúster, que 1Password tenga todo (desde la raíz de homelab):
# tu cuenta
export ONEPASSWORD_ACCOUNT_NAME="Mi Cuenta"
# items y campos: todo ✓
.venv/bin/python ansible/scripts/apply_platform_secrets.py --check
# Secrets que se van a crear, sin valores
.venv/bin/python ansible/scripts/apply_platform_secrets.py --dry-run
Después del playbook y de GitOps:
kubectl -n argocd get secret repo-gitops
kubectl -n arc-runners get secret \
arc-runners-github-app terraform-app tofu-vars
# org antigua, si la usas:
kubectl -n arc-runners-symintel get secret arc-runners-github-app
kubectl -n argocd get applications | grep -E 'arc|terraform'
# controller + listener del scale set
kubectl -n arc-systems get pods
# después del primer apply de OpenTofu
kubectl -n terraform get secret tfstate-default-github
Rotar credenciales¶
Paso a paso completo: Operación — Rotar credenciales.
| Qué | Cómo |
|---|---|
| Private key de una GitHub App | Genera una nueva en GitHub (solo web), reemplaza private_key en 1Password (op item edit <item> "private_key[password]=$(cat llave.pem)"), re-corre playbook-platform-secrets.yml y borra la vieja en GitHub |
Private key de maceosoft-argocd |
Igual que las otras Apps: nueva llave en GitHub, reemplaza private_key, re-corre el playbook y borra la vieja |
| Credenciales FTP | Edita ftp-<repo> (op item edit ftp-<repo> "prod_password[password]=..."), re-corre el playbook y lanza el pipeline de infra (gh workflow run tofu.yml --repo maceosoft/infra --ref main) |
| Webhook de Discord, ping URL de healthchecks.io o contraseña de Grafana | Cambia el campo en su item, re-corre playbook-platform-secrets.yml y sigue Operación — Rotar credenciales |
| Client secret de Dex | Nuevo secret en la OAuth App, actualiza GITHUB_CLIENT_SECRET y corre playbook-dex-oauth-secrets.yml |