8.0 KiB
8.0 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| devops-external-secrets-atlantis | External Secrets / Atlantis / GitHub Actions deep | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
External Secrets / Atlantis / GHA
K8s + Vault + Terraform + CI 의 modern integration. External Secrets Operator (vault → K8s), Atlantis (Terraform PR), GHA (advanced).
📖 핵심 개념
- ESO: 외부 secret store → K8s Secret 자동 sync.
- Atlantis: Terraform 의 GitOps.
- GHA OIDC: cloud auth 가 token 없이.
- Reusable workflow / matrix.
💻 코드 패턴
External Secrets Operator
# SecretStore (Vault 연결)
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-store
spec:
provider:
vault:
server: https://vault.example.com
path: secret
auth:
kubernetes:
mountPath: kubernetes
role: my-role
# ExternalSecret (sync)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1m
secretStoreRef:
name: vault-store
kind: SecretStore
target:
name: db-secret # → K8s Secret
data:
- secretKey: password
remoteRef:
key: secret/myapp/db
property: password
→ App 가 K8s Secret 만 read. Vault 가 source.
AWS Secrets Manager 도
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
→ AWS IRSA (IAM Role for SA).
Auto rotation
# AWS Secrets Manager 가 매 30 days rotate
# ESO 가 매 1 min check + sync
# K8s pod 가 secret mount = 자동 update (eventually)
Pod restart
# Stakater Reloader 가 secret 변경 시 pod restart
metadata:
annotations:
secret.reloader.stakater.com/reload: 'db-secret'
→ Secret 변경 → pod restart → 새 credential.
Atlantis (Terraform 의 GitOps)
# atlantis.yaml
version: 3
projects:
- name: prod-vpc
dir: terraform/prod/vpc
autoplan:
when_modified: ['*.tf', '*.tfvars']
apply_requirements: [approved]
Workflow
1. Engineer 가 PR 가 terraform 변경.
2. Atlantis 가 자동 `terraform plan` → PR comment 에 결과.
3. Reviewer 가 plan 검토.
4. Approved → engineer 가 `atlantis apply`.
5. Atlantis 가 `terraform apply`.
6. PR merge.
→ "Apply 후 merge" — drift 안.
Atlantis 의 lock
매 project 가 1 PR 만 apply 가능.
- A 가 apply 중 → B 가 wait.
- "Apply" PR comment 가 lock 가져.
- 종료 시 release.
→ Concurrent apply 가 conflict 방지.
terraform plan output
$ atlantis plan
+ aws_instance.web
ami = "ami-12345"
instance_type = "t3.micro"
- aws_security_group.old
~ aws_db_instance.main
~ instance_class: "db.t3.micro" -> "db.t3.small"
→ PR 의 visual plan.
Atlantis 의 alternative
- Spacelift (managed, 더 강력)
- Terraform Cloud / HCP Terraform (HashiCorp)
- env0 (managed)
- Terragrunt + custom CI
→ Atlantis 가 OSS + 자체 host.
GitHub Actions OIDC (cloud auth)
# .github/workflows/deploy.yml
permissions:
id-token: write # OIDC token
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/GHA-Deploy
aws-region: us-east-1
- run: aws s3 sync ./build s3://my-bucket
→ Long-lived AWS key X. OIDC token 가 short-lived.
→ AWS / GCP / Azure 가 OIDC trust 설정.
Reusable workflow
# .github/workflows/test.yml (reusable)
on:
workflow_call:
inputs:
node-version:
type: string
default: '20'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: ${{ inputs.node-version }} }
- run: npm ci && npm test
# Caller
jobs:
test:
uses: ./.github/workflows/test.yml
with:
node-version: '22'
Matrix
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [18, 20, 22]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with: { node-version: ${{ matrix.node }} }
→ 9 jobs 가 parallel.
Conditional matrix
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
include:
- os: macos-latest
special: true
exclude:
- os: windows-latest
node: 18
Environment + secrets
jobs:
deploy:
environment: production # → manual approval gate
steps:
- run: ./deploy.sh
env:
API_KEY: ${{ secrets.API_KEY }} # environment-scoped
→ Prod environment 가 별 secrets + manual approval.
Composite action
# .github/actions/setup/action.yml
name: 'Setup'
runs:
using: 'composite'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- shell: bash
run: npm ci
# Use
- uses: ./.github/actions/setup
→ Reusable inline.
Concurrency
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
→ 같은 branch 의 새 push = 옛 cancel.
Cache
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
→ Build 빠름.
Dependabot
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
→ Action 도 자동 update.
Self-hosted runner
runs-on: self-hosted
# 자체 server 가 runner.
→ Cost ↓ (큰 traffic). Setup overhead.
Action security
- Pin to SHA (version 가 mutable).
- uses: actions/checkout@v4.1.0
- uses: actions/checkout@b32f140b0c872d58512e0a66172253c302617b90 # SHA
→ Supply chain 안전.
GitHub Actions 의 secret 주의
Secret value 가 log mask (자동).
하지만:
- 부분 echo 가 가능.
- Forked PR 가 secret access X.
- 외부 action 가 secret access (악성 가능).
→ Pin SHA. Secret 최소화.
Workflow_dispatch (manual)
on:
workflow_dispatch:
inputs:
env:
description: 'Deploy environment'
required: true
type: choice
options: [dev, staging, prod]
→ UI 에서 click 가 trigger.
Schedule
on:
schedule:
- cron: '0 9 * * 1-5' # 평일 9 AM UTC
→ Cron 가 GHA 안.
Workflow run 의 cost
Public repo: 무료.
Private repo:
- 2000 min / month free.
- $0.008 / minute (Linux).
- $0.04 / minute (Windows / macOS).
→ Optimization (cache, matrix exclude) 가 매 cost.
🤔 의사결정 기준
| 작업 | 추천 |
|---|---|
| K8s + Vault | External Secrets Operator |
| Terraform GitOps | Atlantis |
| Cloud auth | GHA OIDC |
| 반복 logic | Reusable workflow / composite action |
| Multi-env | Environment + protection |
| Cost-sensitive | Self-hosted runner |
| Security | Pin SHA |
❌ 안티패턴
- K8s Secret 직접 commit (encrypted SealedSecret 도): rotation 어려움.
- Long-lived AWS key: OIDC.
- 모든 거 inline workflow: reuse 안 됨.
- Secret echo: leak.
- No environment: prod 가 dev 와 같은 gate.
- No concurrency: 중복 deploy.
- Action @main: supply chain.
🤖 LLM 활용 힌트
- ESO 가 K8s + 외부 secret store 의 답.
- Atlantis 가 Terraform 의 GitOps.
- GHA OIDC 가 modern cloud auth.
- Reusable workflow 가 DRY.