Files
2nd/10_Wiki/Topics/Coding/DevOps_External_Secrets_Atlantis.md
T
2026-05-10 22:08:15 +09:00

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
devops
secrets
gitops
vibe-coding
language applicable_to
YAML
DevOps
external secrets operator
Atlantis
Terraform PR
GitHub Actions
OIDC
reusable workflow

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.

🔗 관련 문서