refactor: 폴더 구조 변경
This commit is contained in:
@@ -1,166 +1,156 @@
|
||||
# Project-Infra
|
||||
# Project Infra
|
||||
|
||||
K3s 기반 백엔드 실행 환경을 Git으로 관리하는 개인 프로젝트입니다.
|
||||
[Project-Auth-Server](https://github.com/donghyeon-ka/project-auth-server)가 실제로 실행될 때 필요한 인증 게이트, secret 전달, DB 마이그레이션, 네트워크 정책을 Kubernetes 리소스로 구성했습니다.
|
||||
K3s 기반 인증 플랫폼의 인프라 source-of-truth입니다. 범용
|
||||
`k8s-template`의 lifecycle/ownership 스켈레톤을 적용하고, 기존 리소스를
|
||||
IaC catalog와 Kubernetes desired-state catalog로 분리했습니다.
|
||||
|
||||
이 프로젝트에서 확인하고 싶었던 질문은 네 가지입니다.
|
||||
현재 실제 배포 환경은 폐기 가능한 단일 클러스터용 `lab`입니다. `dev`,
|
||||
`staging`, `prod` IaC root는 확장 위치만 예약되어 있으며 아직 실행 가능한
|
||||
Terraform/OpenTofu 구성이 아닙니다.
|
||||
|
||||
- 로그인 / 세션 처리를 애플리케이션 밖으로 빼면 ingress와 backend의 책임은 어떻게 나뉘는가?
|
||||
- secret을 Vault에 두면서도 Pod는 Kubernetes-native하게 실행할 수 있는가?
|
||||
- default-deny NetworkPolicy 환경에서 백엔드 워크로드가 어떤 통신을 명시해야 하는가?
|
||||
- dev에 집중하되, staging / prod 승격 시 달라질 정책 지점을 overlay 구조로 남길 수 있는가?
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Runtime** | K3s 1.30, Kustomize, Helm, Bash |
|
||||
| **Ingress / Auth** | Traefik, oauth2-proxy, Keycloak Operator |
|
||||
| **Secrets** | HashiCorp Vault, Vault Secrets Operator |
|
||||
| **Data** | PostgreSQL, Flyway, MinIO, Docker Registry |
|
||||
| **Policy** | NetworkPolicy default-deny, PSS Restricted |
|
||||
| **Validation** | `kustomize build`, `kubeconform -strict`, `kube-linter` |
|
||||
| **Scope** | dev overlay 중심. staging / prod는 의도적으로 미구현 |
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||

|
||||
|
||||
큰 흐름은 두 가지입니다.
|
||||
|
||||
- 요청 흐름: `Traefik → oauth2-proxy → auth-server → PostgreSQL / MinIO`
|
||||
- secret 흐름: `Vault → VSO → Kubernetes Secret → Pod envFrom`
|
||||
|
||||
상세 다이어그램:
|
||||
|
||||
- [ForwardAuth cold path](docs/diagrams/sequence/forward-auth-cold.md) / [warm path](docs/diagrams/sequence/forward-auth-warm.md)
|
||||
- [Secret pipeline bootstrap](docs/diagrams/sequence/secret-pipeline-bootstrap.md) / [runtime reconcile](docs/diagrams/sequence/secret-pipeline-runtime.md)
|
||||
- [전체 아키텍처 설명](docs/architecture.md)
|
||||
|
||||
---
|
||||
|
||||
## Engineering Decisions
|
||||
|
||||
### 1. 인증은 Ingress에서 먼저 막고, 백엔드는 JWT를 다시 검증
|
||||
|
||||
Traefik `ForwardAuth → oauth2-proxy → Keycloak` 조합으로 미인증 요청을 ingress 계층에서 먼저 차단합니다.
|
||||
그 뒤 auth-server는 Keycloak JWT를 Spring Security Resource Server로 다시 검증합니다.
|
||||
|
||||
이 구조는 로그인 / 세션 처리와 API 권한 검증을 분리하기 위한 선택입니다. 인증 정책 변경은 애플리케이션 코드보다 Kubernetes manifest 변경으로 다룰 수 있습니다.
|
||||
|
||||

|
||||
|
||||
### 2. Vault는 source of truth, Pod는 Kubernetes Secret만 소비
|
||||
|
||||
Pod마다 Vault Agent sidecar를 붙이지 않고, Vault Secrets Operator가 Vault KV 값을 Kubernetes Secret으로 동기화합니다.
|
||||
## Lifecycle
|
||||
|
||||
```text
|
||||
Vault KV-v2 → VSO reconcile → Kubernetes Secret → Pod envFrom
|
||||
bootstrap/foundation
|
||||
|
|
||||
v
|
||||
infrastructure/live
|
||||
|
|
||||
v
|
||||
bootstrap/gitops
|
||||
|
|
||||
v
|
||||
gitops/clusters ──> platform / policies / tenants / apps
|
||||
```
|
||||
|
||||
Pod는 Vault endpoint, token, template rendering을 직접 알지 않습니다. 대신 secret이 Kubernetes Secret으로 존재하므로, etcd encryption-at-rest가 다음 검증 항목으로 남습니다.
|
||||
- `bootstrap/foundation`: remote state와 초기 identity 같은 선행 조건
|
||||
- `infrastructure/live`: 네트워크, IAM, DNS, load balancer와 클러스터 생성 root
|
||||
- `bootstrap/gitops`: 선택한 GitOps controller와 cluster root 연결
|
||||
- `gitops/clusters`: Kubernetes desired state의 실제 배포 entrypoint
|
||||
|
||||
### 3. Vault role / policy는 도메인별로 분리
|
||||
현재는 Argo CD/Flux가 설치되어 있지 않으므로 `bootstrap/gitops`는 확장
|
||||
계약만 제공합니다. 실제 `lab` 배포는 readiness 경계를 보존하는
|
||||
`scripts/bin/bootstrap.sh`가 ordered stage를 server-side apply합니다.
|
||||
|
||||
VSO Operator의 ServiceAccount는 하나지만, Vault 쪽 role과 policy는 `vso-auth-platform` / `vso-storage`로 나눴습니다.
|
||||
각 `VaultStaticSecret`은 자기 도메인의 `VaultAuth`만 참조합니다.
|
||||
## Repository layout
|
||||
|
||||
auth-platform 권한으로 storage secret 경로에 접근하지 못하게 하려는 결정입니다.
|
||||
| Path | Responsibility |
|
||||
| --- | --- |
|
||||
| `bootstrap/` | foundation 및 GitOps controller bootstrap |
|
||||
| `infrastructure/components/` | 재사용 가능한 compute/database/networking/storage IaC 단위 |
|
||||
| `infrastructure/stacks/` | 반복되는 component 조합 |
|
||||
| `infrastructure/live/<env>/<leaf>/` | 실제 IaC plan/apply와 state 경계 |
|
||||
| `gitops/apps/` | auth-server, PostgreSQL, migration 같은 app 소유 배포 정의 |
|
||||
| `gitops/platform/` | Traefik, Vault, VSO, Keycloak, MinIO, registry와 operator |
|
||||
| `gitops/policies/` | 공통 보안·거버넌스 정책 |
|
||||
| `gitops/tenants/` | namespace, RBAC, quota 같은 tenant 경계 |
|
||||
| `gitops/clusters/lab/main/namespaces`, `stages/` | 현재 실제 배포 entrypoint |
|
||||
| `gitops/clusters/lab/main/all/` | 전체 render/schema/policy 감사 전용; apply 금지 |
|
||||
| `scripts/` | staged bootstrap, teardown와 검증 도구 |
|
||||
| `tests/kustomize-entrypoints.txt` | 검증할 Kustomize entrypoint inventory |
|
||||
|
||||
상세 매핑은 [docs/vault-vso.md](docs/vault-vso.md#vaultauth--vaultstaticsecret-매핑)를 참고합니다.
|
||||
`_template` 디렉터리는 새 component/root를 만들 때 복제하는 뼈대입니다.
|
||||
이 저장소는 이미 실제 `lab` 구성이 조립된 프로젝트이므로 루트에 별도
|
||||
`examples/`를 유지하지 않습니다. 현재 구현을 참고하고 새 단위는 각 책임
|
||||
폴더의 `_template`에서 시작합니다.
|
||||
|
||||
### 4. NetworkPolicy는 default-deny에서 시작
|
||||
|
||||
`mnt` namespace 안에서도 모든 Pod 간 ingress / egress를 기본 차단합니다.
|
||||
새 워크로드를 추가하려면 필요한 통신을 NetworkPolicy로 명시해야 합니다.
|
||||
|
||||
이 마찰은 의도한 것입니다. wide-open으로 시작하는 실수를 줄이고, 워크로드 간 통신 관계를 코드로 남기기 위함입니다.
|
||||
|
||||
상세 매트릭스는 [docs/networking.md](docs/networking.md)를 참고합니다.
|
||||
|
||||
### 5. K3s packaged Traefik manifest는 직접 수정하지 않음
|
||||
|
||||
K3s가 관리하는 Traefik manifest를 직접 수정하면 재부팅 / 재적용 시 덮어써질 수 있습니다.
|
||||
그래서 `HelmChartConfig` overlay와 Middleware / TLSOption 리소스로 운영 정책을 관리합니다.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Repository Layout
|
||||
|
||||
Kustomize `base / components / overlays` 구조입니다.
|
||||
|
||||
| Path | Role |
|
||||
|---|---|
|
||||
| `k8s/base/` | 환경 중립 매니페스트 |
|
||||
| `k8s/components/` | 재사용 component. 현재 ForwardAuth component |
|
||||
| `k8s/overlays/dev/` | 기본 dev 환경. 현재 ForwardAuth component 포함 |
|
||||
| `k8s/overlays/{staging,prod}/` | 의도적으로 비워둔 승격 지점 |
|
||||
| `k8s/scripts/` | bootstrap / validation / reusable tasks |
|
||||
| `terraform/` | contracts만 존재. 추후 구현 |
|
||||
| `docs/` | 상세 설계와 운영 문서 |
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
예를 들어 새 환경과 app을 시작할 때 다음처럼 복제합니다.
|
||||
|
||||
```bash
|
||||
bash k8s/scripts/ci/validate.sh
|
||||
mkdir -p infrastructure/live/dev
|
||||
cp -R infrastructure/live/_template infrastructure/live/dev/cluster
|
||||
|
||||
mkdir -p gitops/clusters/dev
|
||||
cp -R gitops/clusters/_template gitops/clusters/dev/main
|
||||
|
||||
cp -R gitops/apps/_template gitops/apps/example-api
|
||||
```
|
||||
|
||||
`validate.sh`는 주요 overlay에 대해 세 단계를 수행합니다.
|
||||
복제 후 `__REPLACE_ME_*__` 값을 교체하고, 실제 cluster root에서 필요한
|
||||
catalog만 참조합니다.
|
||||
|
||||
1. `kustomize build` — overlay 조립과 patch 유효성 확인
|
||||
2. `kubeconform -strict` — Kubernetes / CRD schema 확인
|
||||
3. `kube-linter` — securityContext, resources, image tag 등 정적 점검
|
||||
|
||||
목표 상태:
|
||||
## Current architecture
|
||||
|
||||
```text
|
||||
k8s/overlays/dev build=ok schema=ok lint=ok
|
||||
k8s/overlays/dev/vso build=ok schema=ok lint=ok
|
||||
Traefik -> oauth2-proxy -> auth-server -> PostgreSQL
|
||||
\-> Keycloak
|
||||
docker-registry -> MinIO
|
||||
|
||||
Vault KV-v2 -> Vault Secrets Operator -> Kubernetes Secret -> workload
|
||||
```
|
||||
|
||||
운영 절차는 [docs/operations.md](docs/operations.md), 실행 매뉴얼은 [guide.md](guide.md)를 참고합니다.
|
||||
- Namespace `mnt`에는 PSS Restricted와 default-deny NetworkPolicy를 적용합니다.
|
||||
- K3s packaged Traefik manifest는 수정하지 않고 `HelmChartConfig`만 관리합니다.
|
||||
- Flyway와 Keycloak realm import는 versioned one-shot operation입니다.
|
||||
- `lab`의 PostgreSQL, Vault와 MinIO는 운영 HA/backup 설계가 아닙니다.
|
||||
|
||||
---
|
||||
## Deploy
|
||||
|
||||
## Current Status
|
||||
```bash
|
||||
export KUBE_CONTEXT_LAB='<expected-context>'
|
||||
bash scripts/bin/bootstrap.sh lab
|
||||
```
|
||||
|
||||
| Area | Status |
|
||||
|---|---|
|
||||
| dev overlay 매니페스트 | 구성됨 (kustomize / kubeconform / kube-linter 검증 가능) |
|
||||
| Vault + VSO 부트스트랩 | idempotent script 로 구성 |
|
||||
| Traefik HelmChartConfig + Middleware | 구성됨 |
|
||||
| NetworkPolicy default-deny | 구성됨 |
|
||||
| ForwardAuth | dev overlay에 포함됨 |
|
||||
| KeycloakRealmImport | overlay 준비됨. 실제 적용 결과 확인 필요 |
|
||||
| cert-manager + ClusterIssuer | manifest 준비됨. 외부 DNS 필요 |
|
||||
| staging / prod overlay | 의도적으로 비워둠 |
|
||||
| Terraform | 디렉토리 contracts만 존재 |
|
||||
배포 순서는 다음과 같습니다.
|
||||
|
||||
---
|
||||
```text
|
||||
namespaces
|
||||
00-platform
|
||||
10-vault
|
||||
20-secrets
|
||||
30-data
|
||||
35-registry
|
||||
40-operations
|
||||
50-apps
|
||||
```
|
||||
|
||||
## Limitations
|
||||
`gitops/clusters/lab/main/all`은 직접 apply하지 않습니다. CRD establishment,
|
||||
Vault 초기화, Secret materialization과 migration 완료는 한 번의 Kustomize
|
||||
apply로 표현할 수 없습니다.
|
||||
|
||||
운영 완료 상태가 아니라 dev 환경에서 실행 구조를 검증한 프로젝트입니다.
|
||||
## Validate
|
||||
|
||||
- Vault는 file backend 단일 노드입니다. dev에서는 secret 전달 경로와 VSO reconcile을 검증하는 데 충분하다고 보고 선택했습니다. prod에서는 `raft` storage와 KMS auto-unseal로 전환해야 합니다.
|
||||
- cert-manager / ClusterIssuer manifest는 있지만, 실제 ACME 인증서 발급은 외부 DNS가 Traefik 진입점을 가리켜야 완료됩니다.
|
||||
- ForwardAuth 로그인 / 로그아웃 / deny-allow E2E 검증은 인증서와 DNS 정리 후 진행할 항목입니다.
|
||||
- Postgres 백업, Terraform 실제 모듈, staging/prod overlay는 아직 구현하지 않았습니다.
|
||||
```bash
|
||||
make doctor
|
||||
make check
|
||||
|
||||
---
|
||||
# CI와 같은 pinned toolchain을 사용한 full gate
|
||||
mise install
|
||||
VALIDATION_PROFILE=full make check
|
||||
```
|
||||
|
||||
`make check`는 템플릿 구조/민감 파일/IaC 계약 검증과 프로젝트별
|
||||
Kustomize/schema/policy/shell/docs 검증을 모두 실행합니다.
|
||||
|
||||
## Extension rules
|
||||
|
||||
- 외부 load balancer, VPC와 DNS는 `infrastructure/components`에서 구현하고
|
||||
`infrastructure/live` root가 조립합니다.
|
||||
- in-cluster ingress/LB controller, Istio 같은 service mesh는
|
||||
`gitops/platform/<unit>`에 두고 cluster stage가 선택합니다.
|
||||
- sidecar는 workload 기본 계약이면 app `base`, 환경별 선택이면 해당
|
||||
`overlays/<env>`에 patch/component로 구성합니다.
|
||||
- VSO와 secret delivery controller는 `gitops/platform/secret-delivery`,
|
||||
실제 비밀값은 Vault에 둡니다.
|
||||
- 규모가 커지면 `live/<provider>/<account>/<region>/<env>/<stack>`과
|
||||
`clusters/<env>/<region>/<cluster>`로 깊이만 확장하고 ownership 경계는
|
||||
유지합니다.
|
||||
|
||||
## Secret incident boundary
|
||||
|
||||
`vault-init-keys.json`은 Git에서 제외되며 로컬 권한은 `0600`이어야 합니다.
|
||||
과거 Git 이력에 포함된 값은 이미 노출된 것으로 간주해야 하므로 실제 Vault
|
||||
root token과 unseal/recovery material을 회전한 뒤, 협업자와 조율하여 원격
|
||||
이력을 별도로 정리해야 합니다.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [docs/architecture.md](docs/architecture.md) — 전체 구조, 워크로드 표, 이미지 정책
|
||||
- [docs/networking.md](docs/networking.md) — NetworkPolicy 매트릭스 / 작성 규칙
|
||||
- [docs/ingress-traefik.md](docs/ingress-traefik.md) — Traefik, ForwardAuth, cert-manager, KeycloakRealmImport
|
||||
- [docs/vault-vso.md](docs/vault-vso.md) — Vault auth, policy/role, VSO Secret catalog
|
||||
- [docs/operations.md](docs/operations.md) — bootstrap 단계, validate.sh, 환경별 차등
|
||||
- [docs/troubleshooting.md](docs/troubleshooting.md) — 운영 중 만난 함정 7건 (사건 카탈로그)
|
||||
- [docs/diagrams/architecture/](docs/diagrams/architecture/) — draw.io 아키텍처 그림
|
||||
- [docs/diagrams/sequence/](docs/diagrams/sequence/) — Mermaid sequence diagrams
|
||||
- [guide.md](guide.md) — 실제 실행 매뉴얼
|
||||
- [실행 가이드](guide.md)
|
||||
- [프로젝트 아키텍처](docs/architecture.md)
|
||||
- [스켈레톤 구조 계약](docs/architecture/repository-structure.md)
|
||||
- [운영과 검증](docs/operations.md)
|
||||
- [Vault와 VSO](docs/vault-vso.md)
|
||||
- [Ingress와 Traefik](docs/ingress-traefik.md)
|
||||
- [보안 강화](docs/security-hardening.md)
|
||||
- [장애 기록](docs/troubleshooting.md)
|
||||
- [템플릿 사용 가이드](docs/guides/getting-started.md)
|
||||
|
||||
Reference in New Issue
Block a user