refactor: reorganize GitOps control plane
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
# Argo CD layout
|
||||
|
||||
`bootstrap/argocd/root-application.yaml`이 유일한 수동 seed입니다. 이
|
||||
Application은 `clusters/dev-k3s`를 source로 사용하고 다음 리소스를
|
||||
소유합니다.
|
||||
|
||||
```text
|
||||
clusters/dev-k3s
|
||||
├── projects
|
||||
└── applications
|
||||
├── foundation
|
||||
│ ├── sealed-secrets
|
||||
│ ├── vault
|
||||
│ └── vault-agent-injector
|
||||
├── platform
|
||||
│ └── auth-system
|
||||
└── workloads
|
||||
├── auth-server
|
||||
└── api-server
|
||||
```
|
||||
|
||||
AppProject는 root sync wave `-10`, foundation은 `0~1`, platform은 `10`,
|
||||
workload는 `20`입니다. 이 wave는 child Application 객체 생성 순서만
|
||||
표현하며 서로 다른 Application의 readiness dependency로 사용하지
|
||||
않습니다. Vault Agent와 workload는 필요한 Vault/DB API가 준비될 때까지
|
||||
자체 retry 가능한 형태여야 합니다.
|
||||
|
||||
모든 child Application은 auto-sync, prune, self-heal을 사용합니다.
|
||||
Application 삭제와 parent prune은 확인이 필요하며, shared resource
|
||||
소유권 충돌은 `FailOnSharedResource=true`로 실패시킵니다.
|
||||
|
||||
Sync hook이 있는 `auth-server`와 `auth-system`에는 selective sync 옵션을
|
||||
사용하지 않습니다. DB migration과 Keycloak client sync는 같은
|
||||
Application 내부 wave로 순서를 제어합니다.
|
||||
|
||||
클러스터가 하나이고 child Application 수가 적으므로 현재는 명시적
|
||||
Application을 사용합니다. 두 번째 클러스터나 실제 production이 생길
|
||||
때 foundation/platform/workload별 ApplicationSet 도입을 검토합니다.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Deployment architecture
|
||||
|
||||
## Reconciliation boundaries
|
||||
|
||||
```text
|
||||
Gitea main
|
||||
|
|
||||
+-- Argo CD root -> AppProjects + child Applications -> Kubernetes
|
||||
|
|
||||
+-- approved Terraform runner -> Vault API
|
||||
```
|
||||
|
||||
Argo CD는 Kubernetes desired state만 관리합니다. 최초 Argo 설치/root
|
||||
seed와 문서화된 recovery 외에는 직접 cluster mutation을 하지 않습니다.
|
||||
Terraform은 Config Management Plugin이나 Argo hook 안에서 실행하지
|
||||
않습니다.
|
||||
|
||||
## Kustomize ownership
|
||||
|
||||
- `platform/`, `workloads/`: 환경 중립 base
|
||||
- `clusters/dev-k3s/manifests/`: namespace, host, image, Vault role 및
|
||||
NetworkPolicy를 포함하는 최종 cluster composition
|
||||
- Argo CD Application: final composition만 source로 사용
|
||||
|
||||
지원하지 않는 production overlay는 존재하지 않습니다. production
|
||||
계약과 승인 경계가 확정될 때 별도로 생성합니다.
|
||||
|
||||
## In-application ordering
|
||||
|
||||
`auth-server`의 한 sync operation 안에서:
|
||||
|
||||
- generated ConfigMap과 일반 리소스: wave `0`
|
||||
- database migration Sync hook: wave `5`
|
||||
- Deployment: wave `10`
|
||||
- north-south route: wave `20`
|
||||
|
||||
`auth-system`의 Keycloak client sync도 idempotent Sync hook이며 deadline,
|
||||
backoff, `BeforeHookCreation,HookSucceeded` cleanup을 사용합니다.
|
||||
|
||||
## Stateful lifecycle
|
||||
|
||||
Vault와 PostgreSQL PVC는 `Prune=false`로 보호합니다. child Application
|
||||
prune/delete는 확인이 필요합니다. path 이동이나 Application rename 전에는
|
||||
새 owner가 동일 live resource를 정상적으로 추적하는지 확인한 후 이전
|
||||
owner를 non-cascading 방식으로 제거합니다.
|
||||
|
||||
## Image promotion
|
||||
|
||||
첫-party image는 애플리케이션 CI가 얻은 정확한 GHCR digest를 Gitea
|
||||
workflow에 전달합니다. workflow는 digest 변경 PR을 만들고, validation과
|
||||
승인을 거쳐 merge된 뒤 Argo CD가 배포합니다.
|
||||
|
||||
현재 short-SHA tag는 migration 시점의 예외입니다. private GHCR을 읽을
|
||||
자격증명이 이 저장소 실행 환경에 없으므로 임의 digest로 바꾸지 않았고,
|
||||
다음 정상 promotion에서 `digest:`로 교체됩니다.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Secret trust boundaries
|
||||
|
||||
## Dev Vault
|
||||
|
||||
`dev-k3s`는 단일 self-hosted Vault를 사용합니다. 동일 workload
|
||||
클러스터에 별도의 Transit Vault를 두지 않습니다. 단일 Vault는 다음을
|
||||
소유합니다.
|
||||
|
||||
- KV-v2 runtime secret path
|
||||
- Kubernetes auth와 workload role
|
||||
- dynamic PostgreSQL credential
|
||||
- 애플리케이션 JWT signing용 Transit key
|
||||
|
||||
dev Vault는 Shamir 1-of-1로 한 번 초기화하고 재시작 시 명시적으로
|
||||
unseal합니다. 이 방식은 개발 환경 전용입니다. production에서는 managed
|
||||
Vault 또는 독립 failure domain의 HA integrated-Raft와 KMS/HSM
|
||||
auto-unseal을 사용해야 합니다.
|
||||
|
||||
## Terraform
|
||||
|
||||
`vault-core` state는 mounts, auth, policies, roles와 JWT key를 소유하며
|
||||
제한된 관리자만 적용합니다. `vault-database`는 PostgreSQL connection과
|
||||
dynamic roles만 소유하고 `vault-database-automation-dev` 정책을 사용합니다.
|
||||
|
||||
Terraform variable로 전달되는 token과 PostgreSQL password는 ephemeral/
|
||||
write-only 경계를 사용합니다. KV payload는 Terraform resource/data
|
||||
source로 읽거나 쓰지 않습니다.
|
||||
|
||||
## Workload authentication
|
||||
|
||||
workload는 audience `vault`, TTL 1시간의 projected ServiceAccount token으로
|
||||
Vault Kubernetes auth에 로그인합니다. token은 Vault Agent가 사용하며
|
||||
application container에 Kubernetes bearer token을 직접 노출하지 않습니다.
|
||||
|
||||
Secret payload는 승인된 운영자가 Vault에 직접 기록합니다. 값은 Git,
|
||||
Gitea Actions log, Terraform state, Kubernetes manifest에 남기지 않습니다.
|
||||
|
||||
## Bootstrap material
|
||||
|
||||
Vault init output은 기본적으로 `.local/vault/dev-k3s-init.json`에 mode
|
||||
`0600`으로 생성됩니다. encrypted custody로 이동한 후 working copy를
|
||||
제거합니다. initial root token은 `vault-core`와 operator auth 검증 직후
|
||||
폐기합니다.
|
||||
|
||||
Sealed Secrets는 private GHCR pull credential에만 사용합니다. controller
|
||||
private key는 별도 복구 저장소에 백업해야 합니다.
|
||||
|
||||
## Dev limitations
|
||||
|
||||
- Vault, PostgreSQL, ingress가 아직 TLS를 사용하지 않음
|
||||
- single-node Vault와 PostgreSQL
|
||||
- Kubernetes API egress CIDR가 현재 dev cluster에 종속
|
||||
- 정적 bootstrap secret은 coordinated rotation 필요
|
||||
|
||||
이 제약은 production에서 허용되지 않습니다.
|
||||
Reference in New Issue
Block a user