인셔셔RSS 관심 있는 블로그, 뉴스, 기술 정보를 효율적으로 추적하고 읽으세요
원문 읽기 InertiaRSS에서 열기

추천 피드

WordPress大学
WordPress大学
G
Google Developers Blog
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
I
InfoQ
Last Week in AI
Last Week in AI
博客园 - 司徒正美
T
Tailwind CSS Blog
博客园 - 三生石上(FineUI控件)
Jina AI
Jina AI
小众软件
小众软件
李成银的技术随笔
T
The Blog of Author Tim Ferriss
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
L
LangChain Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
月光博客
月光博客

DEV Community

🧠 Hermes Agent Assistant — A Modular AI Agent System with Planner, Executor & Memory Spring Boot Auto-Configuration Source Code: Nail This Interview Question The Ultimate Guide to Free AI API Keys: 6 Platforms You Need to Know Why 91% of AI Agents Fail in Production (And What the 9% Do Differently) TryHackMe | Battery | WALKTHROUGH Stop Guessing Your Regex — Test It Live in the Browser I Built FreelancEye, an Open-Source Mobile PWA for Finding Clients Beyond the Hype: My Production Playbook for Docker Swarm Top AI App Builder Platforms with Integrated Backend, Hosting & Database ECS vs EKS in 2026: An Honest Comparison from Someone Who Has Run Both in Production Hardening Your Node.js App Against Supply Chain & Remote Code Execution Attacks linux commands A Practical GEO Case: How an AI System Started Recommending Our Blog Your AI Agent Works 24/7 and Earns $0. I Built the Fix. Your AI Trading Agent Will Lose All Your Money — Here's How To Stop It Google I/O 2026: What Happens When Everything Connects? Why AI writes software but doesn’t build a good product Beyond the Hype: How Google I/O 2026 Secretly Democratized Production-Ready AI Agents with Managed Sandboxes. The Killer Assumption Test: How to Spot Doomed Product Decisions Before You Ship Stop Describing Your Bugs — Just Screenshot Them # I Built an AI Website Builder and Here's What Actually Happened Cooking an AI Campaign in 5 Minutes with Google Cloud AI APIs Your PM Retrospectives Are Lying to You How I Built a Free, Self-Hosted Pipeline That Auto-Generates Faceless YouTube Shorts TypeScript 54 to 58: The Features That Actually Matter in 2026 How to Tailor Your CV to Any Job Posting in 2026 The 7-day SaaS MVP loop: ship fast, then validate with people who actually show up 95. Fine-Tuning LLMs: Make a General Model Do Your Specific Job What Is a Frontend Developer Roadmap and Why You Need One Google shipped three Gemini "Flash" models. Picking the wrong one could 6 your AI bill Building an MCP server so Claude can query my SaaS analytics directly Google I/O 2026 and the Rise of the AI Ecosystem Your Docker Builds Are Slow Because You're Doing It Wrong (And I Built a Tool to Prove It) How do you verify GitHub contributions without trusting self-reported skills? CV vs Resume: What's the Difference and Which Do You Need? student Devs: Build AI Agents & Compete for $55K in Prizes 🚀 How to Write a Cover Letter That Actually Gets You Interviews Battle-Tested: What Getting Hacked Taught Me About Web & Cyber Security Unda folders za kuandika code >> mkdir src >> cd src >> mkdir controllers database routes services utils >> cd .. Directory: C:\Users\mwaki\microfinance-system Mode LastWriteTime Length Name Code Coverage .NET AI slop debt" is technical debt on fast forward. Nobody's ready. Multi-Head Latent Attention (MLA) Memoria - A Local AI Reading Companion Powered by Gemma 4 Stop Trusting Your Accuracy Score: A Practical Guide to Evaluating Logistic Regression Models Serious Question: Is the Developer Job Actually in Risk Due to AI? published: true tags: #discuss #career #ai #help rav2d: We ported an AV2 video decoder from C to Rust — here's why Your New Domain's First Week of GA4 Is a Lie: 4 Days of Raw Data from a Launch Gemma Guide - Real-Time Spatial Awareness for Blind Users From YAML to AI Agents: Building Smarter DevOps Pipelines with MCP A Field Guide to Human–AI Relations (For the Newly Bewildered Mortal)
AWS Secrets Manager에 Kamal 비밀을 저장하고 저렴한 Hetzner VPS에 배포합니다
Derrick Amen · 2026-05-23 · via DEV Community

Derrick Amenuve

카마르와 문제가 발생했습니다. 제 .kamal/secrets 파일에는 노출된 API 키들이 제 노트북에 있었습니다. 접근할 수 있는 누구나 그것들을 읽을 수 있었습니다.

TLDR; 카마르AWS Secrets Manager와 함께 사용하고 Hetzner VPS에 배포하세요. 평문 비밀이 없고 저렴한 호스팅, 규정 준수에 만족합니다.

문제

카마ル은 애플리케이션 배포에 매우 좋습니다. 하지만 기본적으로 비밀번호는 평문 파일에 저장됩니다. SOC 2와 GDPR에 그렇게 하면 안 됩니다. 관리형 저장소가 필요합니다. 저는 AWS Secrets Manager를 선택했습니다.

그런데 그 다음에 다른 문제에 부딪혔습니다. kamal secrets fetch --adapter aws_secrets_manager 명령어는 --from 각 키가 자신만의 AWS 비밀번호여야 합니다. 모든 것을 JSON 덩어리로 저장하면 (저는 그렇게 했지만), 다음과 같은 결과가 나옵니다:

ERROR (RuntimeError): myapp/production/secrets//DEEPGRAM_API_KEY: Secrets Manager can't find the specified secret.

전체 화면 모드로 전환 전체 화면 모드 종료

단계 1: Hetzner VPS

Hetzner CAX 시리즈는 월 약 4 유로부터 시작합니다. CX22를 사용하며, 2개의 vCPU와 4GB RAM을 사용합니다. 생산에 충분합니다.

# On your Hetzner server
apt update && apt install -y docker.io

# Copy your SSH key so Kamal can connect
ssh-copy-id root@your-server-ip

전체 화면 모드로 전환 전체 화면 모드 종료

당신의 config/deploy.yml:

servers:
  web:
    hosts:
      - runtime.yourdomain.com

proxy:
  ssl: true
  hosts:
    - runtime.yourdomain.com
  healthcheck:
    path: /health/ready

registry:
  server: docker.io
  username: your-docker-user
  password:
    - KAMAL_REGISTRY_PASSWORD

전체 화면 모드로 전환 전체 화면 모드 종료

Docker Hub 계정과 개인 접근 토큰이 필요합니다KAMAL_REGISTRY_PASSWORD.

단계 2: AWS에서 비밀 정보 생성

AWS 비밀 정보 관리자 콘솔에서:

  1. 비밀 정보 관리자로 이동>새로운 비밀 정보 저장
  2. "다른 종류의 비밀"
  3. 텍스트 탭으로 전환하고 JSON을 붙여넣으세요
{
  "DEEPGRAM_API_KEY": "your_deepgram_key",
  "ASSEMBLY_AI_API_KEY": "your_assemblyai_key",
  "REDIS_URL": "redis://:password@your-redis:6379",
  "KAMAL_REGISTRY_PASSWORD": "your_docker_token"
}

전체 화면 모드 입력 전체 화면 모드 종료

  1. 이름을 지정하세요myapp/production/secrets
  2. 저장 버튼 클릭

서버 근처의 지역을 선택하세요. Hetzner 박스가 독일에 있으면 eu-central-1 (프랑크푸르트)를 사용하세요. 지연 시간을 낮추고 GDPR을 만족시킵니다.

단계 3: 노트북용 IAM 사용자

노트북이 배포 중 비밀을 읽을 권한이 필요합니다.

  1. IAM > 사용자 > 사용자 생성
  2. 이름을 kamal-deploy
  3. 콘솔 접근을 취소 (CLI만 허용)
  4. 그룹을 생성하며secrets-manager SecretsManagerReadWrite 정책
  5. 배치 읽기용 인라인 정책 추가:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:BatchGetSecretValue",
        "secretsmanager:ListSecrets"
      ],
      "Resource": "*"
    }
  ]
}

전체 화면 모드 입력 전체 화면 모드 종료

  1. 사용자를 그룹에 추가

IAM 정책은 몇 분이 걸릴 수 있습니다. 처음에 실패하면 30초를 기다리고 다시 시도하세요.

단계 4: AWS CLI 설정

aws configure
# AWS Access Key ID: paste from IAM user
# AWS Secret Access Key: paste
# Default region name: eu-central-1
# Default output format: json

전체 화면 모드 입력 전체 화면 모드 종료

테스트하세요:

aws secretsmanager get-secret-value --secret-id myapp/production/secrets --query SecretString --output text | head -c 50

전체 화면 모드 입력 전체 화면 모드 종료

JSON의 시작을 볼 수 있어야 합니다.

단계 5: .kamal/secrets 파일 형식 지정

여기서 멈췄습니다. --from 플래그는 각 키당 하나의 AWS 비밀번호를 요구합니다. 20개의 분리된 비밀번호는 지루합니다. 확인하세요Kamal 비밀 문서에 대해 더 알아보려면.

대신 Python으로 추출하여 AWS CLI를 사용합니다. 각 줄은 독립적입니다:

# AWS Secrets Manager: myapp/production/secrets (eu-central-1)
DEEPGRAM_API_KEY=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['DEEPGRAM_API_KEY'])" "$(aws secretsmanager get-secret-value --secret-id myapp/production/secrets --query SecretString --output text)")
ASSEMBLY_AI_API_KEY=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['ASSEMBLY_AI_API_KEY'])" "$(aws secretsmanager get-secret-value --secret-id myapp/production/secrets --query SecretString --output text)")
REDIS_URL=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['REDIS_URL'])" "$(aws secretsmanager get-secret-value --secret-id myapp/production/secrets --query SecretString --output text)")
KAMAL_REGISTRY_PASSWORD=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['KAMAL_REGISTRY_PASSWORD'])" "$(aws secretsmanager get-secret-value --secret-id myapp/production/secrets --query SecretString --output text)")

전체 화면 모드 입력 전체 화면 모드 종료

각 줄은 전체 JSON을 가져와 하나의 키를 추출합니다. Kamal은 각 줄을 자신만의 하위 셸에서 평가하므로 줄 간에 공유 변수가 없습니다. 이 작동합니다.

또한 jq를 선호하시면 사용할 수 있습니다:

DEEPGRAM_API_KEY=$(aws secretsmanager get-secret-value --secret-id myapp/production/secrets --query SecretString --output text | jq -r '.DEEPGRAM_API_KEY')

전체 화면 모드 입력 전체 화면 모드 종료

단계 6: 배포

kamal deploy

전체 화면 모드 입력 전체 화면 모드 종료

Kamal은 배포 중 AWS에서 비밀을 가져와 컨테이너에 주입합니다. 평문 파일은 결코 서버에 접촉하지 않습니다.

제작 및 배포

각 환경마다 다른 AWS 비밀번호를 사용합니다. 두 환경 모두 AWS에서 텍스트 없이 가져옵니다.

# .kamal/secrets  (used by kamal deploy)
DEEPGRAM_API_KEY=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['DEEPGRAM_API_KEY'])" "$(aws secretsmanager get-secret-value --secret-id myapp/production/secrets --query SecretString --output text)")
KAMAL_REGISTRY_PASSWORD=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['KAMAL_REGISTRY_PASSWORD'])" "$(aws secretsmanager get-secret-value --secret-id myapp/production/secrets --query SecretString --output text)")

# .kamal/secrets.staging  (used by kamal deploy -d staging)
DEEPGRAM_API_KEY=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['DEEPGRAM_API_KEY'])" "$(aws secretsmanager get-secret-value --secret-id myapp/staging/secrets --query SecretString --output text)")
KAMAL_REGISTRY_PASSWORD=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['KAMAL_REGISTRY_PASSWORD'])" "$(aws secretsmanager get-secret-value --secret-id myapp/staging/secrets --query SecretString --output text)")

전체 화면 모드로 입력 전체 화면 모드 종료

파일 간에는 비밀번호 이름만 변경됩니다.myapp/production/secrets 생산용, myapp/staging/secrets 배포용입니다.kamal deploy -d staging를 실행하면 Kamal이 배포 파일을 읽습니다.

두 비밀이 AWS에 있습니다. 평문의 스테이징 자격 증명도 없습니다. 이는 SOC 2에 중요합니다 왜냐하면 감사인은 모든 환경을 확인하기 때문입니다.

완료되었습니다

더 이상 평문의 비밀이 없습니다. SOC 2와 GDPR 요구 사항을 충족했습니다. Hetzner 청구서는 한 달에 5 유로 미만으로 유지됩니다.

큰 감사를 AWS 문서 팀에게, 그리고 Kamal 유지 관리자들에게 드립니다Hetzner를 통해 호스팅 비용을 합리적으로 유지해 주셔서 감사합니다. 이것이 제가 마주했던 고통을 덜어줄 수 있기를 바랍니다. 이제 다시 개발로 돌아가겠습니다.