email + eml + sync
# EML 파일명을 Maildir 규칙에 맞게 변경 (예: 타임스탬프 활용)
for eml in *.eml; do
new_name=$(date +%s%N).$(hostname).eml
cp "$eml" "/tmp/maildir/new/$new_name"
done
어쩌다 보니 이메일을 파싱해서 특정 보험건에 대한 요율을 추출해야 하는 상황이되어 제반 준비를 하다 발견했다.
위 shell에서 “date +%s%N"의 의미를 몰라 찾아보니.
date 명령의 형식을 지정하는 파라미터였다. 음. 위 방식을 unix 나노초를 반환하는 것이다.
그런데 뒤쪽의 hostname은 왜 필요한 것일까? (그냥 식별하는 용으로 보인다.)
gcp + apigee + SpikeArrest
![]() |
|---|
| SpikeArrest works |
apigee의 traffic management를 보다가 생각한다.
그 짧은 순간에 이전과 이후의 요청을 어떻게 구분한 것인지 말이다.
구글의 엔지니어들은 양동이 개념을 도입해서 요청이 들어오면 평가하는 것이 아니라, 각 요청들을 하나의 양동이에 담고, 그 양동이 시간이 되면 퍼내는 식으로 구현을 했다.
참고할 만하다.
Win 시계가 자꾸만 틀림.
시스템을 설치하고 Window로 부팅하는 경우 시간이 자꾸 틀려서(==동기화가 안 되어서) MS가 다되었다 생각하고 있었는데 말이다.
오늘 몇 달만에 Window로 부팅을 했더니, 시간이 꼭 UTC라는 느낌이 들어 분을 보니 동일하다.
윈도우와 리눅스 듀얼부트 환경 대부분의 리눅스 배포판은 하드웨어(메인보드) 시계를 UTC로 저장하는 반면, 윈도우는 기본적으로 하드웨어 시계를 로컬 타임(한국 기준 KST 등)으로 간주합니다. 이로 인해 두 운영체제를 번갈아 부팅할 때 시간이 맞지 않거나, 윈도우에서 시간이 UTC 기준으로 표시되는 문제가 발생할 수 있습니다
그렇다고 합니다. 딱히 수정할 생각은 없다.
sops + container
SOPS를 Docker에 포함하는 대표적 사례
SOPS(Secrets OPerationS)는 Docker 환경에서 다양한 방식으로 통합·활용되고 있습니다. 아래는 실제 사례와 구현 방법, 그리고 주요 활용 패턴을 정리한 내용입니다.
1. SOPS 바이너리 내장 Docker 이미지 생성
- 방법: Dockerfile에서 SOPS 바이너리를 직접 다운로드해 이미지에 포함시킵니다.
- 예시:
FROM alpine:latest
# SOPS 설치
RUN wget https://github.com/mozilla/sops/releases/download/v3.8.1/sops-v3.8.1.linux.amd64 -O /usr/local/bin/sops \
&& chmod +x /usr/local/bin/sops
# age(옵션) 설치
RUN wget https://github.com/FiloSottile/age/releases/download/v1.1.1/age-v1.1.1-linux-amd64.tar.gz -O /usr/local/bin/age \
&& chmod +x /usr/local/bin/age
# 필요에 따라 키 파일, 설정 파일 등을 COPY
COPY ./src/generate_sops_config.sh /app/config/generate_sops_config.sh
RUN chmod +x /app/config/generate_sops_config.sh
# 추가적으로 키 생성, .sops.yaml 생성 등 스크립트 실행 가능
ENTRYPOINT ["sops"]
2. SOPS를 활용한 컨테이너 환경변수 주입
- 방법: SOPS의
exec-env기능을 활용하여, 암호화된 시크릿 파일을 복호화해 Docker 컨테이너에 환경변수로 주입합니다. - 예시:
sops exec-env secret.enc.json 'docker run --rm -it -e PASSWORD_1=$PASSWORD_1 alpine sh -c "echo $PASSWORD_1"'
- `secret.enc.json` 파일을 복호화해 환경변수로 만들고, 해당 환경변수를 컨테이너에 전달합니다.
- Docker Compose 연동:
sops exec-env secret.enc.json 'docker compose up'
- 환경변수는 오직 해당 프로세스에서만 유효하며, 안전하게 임시로 전달됩니다[^4].
3. SOPS + HashiCorp Vault 등 외부 시크릿 관리와 연동
- 방법: Vault, AWS KMS, GCP KMS 등 외부 시크릿 관리 시스템과 SOPS를 연동하여, Docker 컨테이너에서 안전하게 시크릿을 복호화·활용합니다.
- 예시: Vault를 Docker 컨테이너로 띄우고, SOPS가 Vault의 키로 시크릿을 암호화/복호화하도록 설정3.
4. .sops.yaml로 파일별 암호화 정책 자동화
- 방법:
.sops.yaml파일을 Docker 이미지에 포함시키거나, 볼륨 마운트로 전달하여 환경별(예: dev, prod)로 각기 다른 KMS 키, PGP 키 등을 자동 지정할 수 있습니다. - 예시:
creation_rules:
- path_regex: \.dev\.yaml$
kms: "arn:aws:kms:us-east-1:111111111111:key/xxx-xxx-xxx"
- path_regex: \.prod\.yaml$
kms: "arn:aws:kms:us-east-1:111111111111:key/yyy-yyy-yyy"
- pgp: "A2B73FB4DA0891B38EECD35B47991CD146C9C4BC"
- 파일명 패턴에 따라 자동으로 암호화 키를 선택[^5].
5. 실전 활용 패턴
- CI/CD 파이프라인: SOPS 내장 이미지를 사용해 빌드/배포 과정에서 시크릿 복호화 및 환경변수 주입 자동화
- 로컬 개발/운영 환경: SOPS 내장 컨테이너로 시크릿 파일 관리, 복호화, 테스트 일관성 확보
- 컨테이너화된 시크릿 관리: SOPS를 포함한 컨테이너를 별도의 유틸리티로 활용, 필요 시 볼륨 마운트로 시크릿 파일 주입
요약
- SOPS는 Docker 이미지에 바이너리로 포함해 사용할 수 있으며, 환경변수 주입, 시크릿 복호화, 외부 시크릿 관리 시스템과의 연동 등 다양한 활용 사례가 있습니다.
sops exec-env를 통한 환경변수 주입,.sops.yaml로 파일별 암호화 정책 지정, Vault 등 외부 서비스와의 연동이 대표적입니다.- CI/CD, 개발, 운영 등 다양한 환경에서 SOPS 내장 Docker 이미지를 활용하면 시크릿 관리의 일관성과 보안성을 크게 높일 수 있습니다1243.
JWT +JWS
JWT와 JWS 비교
| 구분 | JWT (JSON Web Token) | JWS (JSON Web Signature) |
|---|---|---|
| 정의 | JSON 형식의 claims(정보)를 안전하게 표현하는 토큰 포맷 | 데이터(주로 JWT)를 디지털 서명으로 무결성 보호하는 방식 |
| 구조 | Header, Payload, (Signature 또는 암호화) | Header, Payload, Signature |
| 목적 | 정보(Claims) 전달 및 인증/인가 등 | 데이터 위변조 방지(무결성 보장) |
| 서명/암호화 | 서명(JWS), 암호화(JWE), 둘 다 또는 없음 가능 | 반드시 서명만 지원, 암호화는 지원하지 않음 |
| Payload 형식 | 반드시 JSON 객체 | 어떤 바이너리든 가능(JSON, 바이너리, 텍스트 등) |
| 사용 예시 | 인증 토큰, 정보 전달 등 | JWT의 서명, 일반 데이터의 서명 등 |
상세 설명
- JWT란? JWT는 JSON 객체로 구성된 claims(정보 묶음)을 안전하게 표현하는 표준 포맷입니다. JWT는 서명(JWS 구조) 또는 암호화(JWE 구조)를 통해 무결성 또는 기밀성을 보장할 수 있습니다. 즉, JWT는 JWS 또는 JWE 구조로 만들어질 수 있으며, 가장 일반적인 JWT는 JWS 구조(서명된 JWT)입니다1234.
- JWS란? JWS는 데이터(주로 JWT의 payload)를 디지털 서명하여, 위변조되지 않았음을 증명하는 표준입니다. JWS는 Header, Payload, Signature 세 부분으로 구성되며, 서명 알고리즘(HMAC, RSA, ECDSA 등)을 사용합니다. JWS의 Payload는 반드시 JSON일 필요는 없으며, 바이너리 등 다양한 형식이 가능합니다1534.
- 관계
- 보안성
- JWS는 서명만 지원하므로, 누구나 Payload를 볼 수 있지만 위변조 여부는 검증 가능합니다.
- JWE는 암호화를 통해 Payload 자체를 숨길 수 있습니다3.
요약
- JWT는 정보를 안전하게 표현하는 “컨테이너"이며,
- JWS는 그 컨테이너(혹은 임의의 데이터)에 “서명"을 부여하는 방식입니다.
- JWT의 가장 흔한 구현이 JWS 구조(서명된 JWT)입니다.
- JWS는 JSON뿐 아니라 다양한 데이터 형식을 서명할 수 있습니다134.
OAuth Grant Type란?
OAuth Grant Type란?
OAuth 2.0의 Grant Type(권한 부여 유형)은 클라이언트가 인증 서버로부터 액세스 토큰을 받기 위해 사용하는 인증 및 권한 위임 방식입니다. 각각의 Grant Type은 다양한 환경(웹, 모바일, 서버 등)과 보안 요구사항에 맞춰 설계되어 있으며, 각 방식마다 인증 절차와 필요한 정보가 다릅니다123.
주요 OAuth 2.0 Grant Type 종류
| Grant Type | 특징 및 사용 환경 | 주요 용도 |
|---|---|---|
| Authorization Code | 서버사이드(웹) 애플리케이션, 가장 안전 | 사용자가 브라우저에서 인증 후, 클라이언트가 받은 코드를 서버에서 토큰으로 교환245 |
| PKCE (Proof Key for Code Exchange) | 모바일/SPA 등 공개 클라이언트, Authorization Code 보안 강화 | 코드 탈취 방지, 추가 검증값(code verifier/challenge) 사용24 |
| Implicit (Deprecated) | SPA, 모바일 등 클라이언트 사이드 | 토큰을 브라우저로 직접 반환, 보안 취약해 OAuth 2.1에서 폐기 예정245 |
| Resource Owner Password Credentials (Deprecated) | 신뢰할 수 있는 앱(내부), 보안 취약 | 사용자의 ID/PW를 직접 받아 토큰 발급, 외부 앱에는 권장하지 않음24 |
| Client Credentials | 서버 간 통신, 사용자 개입 없음 | 클라이언트의 ID/Secret만으로 토큰 발급, 서버-서버, 데몬 등245 |
| Device Code | 입력장치 제한된 디바이스(스마트TV 등) | 별도 기기에서 인증 후 디바이스에 토큰 발급5 |
| Refresh Token | Access Token 재발급 | Access Token 만료 시 재인증 없이 새 토큰 발급, Authorization Code/Password 방식에서 주로 사용24 |
각 Grant Type의 간단 설명
1. Authorization Code Grant
gcp + apigee + attach
export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
echo "PROJECT_ID=${PROJECT_ID}"
export INSTANCE_NAME=eval-instance
export ENV_NAME=eval
export PREV_INSTANCE_STATE=
echo "waiting for runtime instance ${INSTANCE_NAME} to be active"
while : ; do
export INSTANCE_STATE=$(
curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
-X GET "https://apigee.googleapis.com/v1/organizations/${PROJECT_ID}/instances/${INSTANCE_NAME}" |
jq "select(.state != null) | .state" --raw-output
)
[[ "${INSTANCE_STATE}" == "${PREV_INSTANCE_STATE}" ]] || (
echo
echo "INSTANCE_STATE=${INSTANCE_STATE}"
)
export PREV_INSTANCE_STATE=${INSTANCE_STATE}
[[ "${INSTANCE_STATE}" != "ACTIVE" ]] || break
echo -n "."
sleep 5
done
echo
echo "instance created, waiting for environment ${ENV_NAME} to be attached to instance"
while : ; do
export ATTACHMENT_DONE=$(
curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
-X GET "https://apigee.googleapis.com/v1/organizations/${PROJECT_ID}/instances/${INSTANCE_NAME}/attachments" |
jq "select(.attachments != null) | .attachments[] | select(.environment == \"${ENV_NAME}\") | .environment" --join-output
)
[[ "${ATTACHMENT_DONE}" != "${ENV_NAME}" ]] || break
echo -n "."
sleep 5
done
echo "***ORG IS READY TO USE***"
apigee를 테스트해 보면서 제일 적응 안 되는 부분이 인스턴스를 붙이는 부분이라고 생각된다.
GCP + apigee + debug
![]() |
|---|
| apigee debug |
GCP apigee 세션을 진행하다보니 각 호출에 대해 디버깅 할 수 있는 Step이 있어 기록으로 남겨본다.
REST 응답에 meta data를 포함하는 것
![]() |
|---|
| rest 응답에 메타정보를 포함하는 방식 |
REST API 설계의 기본이라는 동영상을 보다보니, 데이터 이외에 메타정보를 포함하는 내용이 나온다.
REST를 구성하면서 한 번도 생각해 본적이 없는 것이라 살짝 당혹스럽다.
물론 차세대라고 불리는 SI 할 때는 응답전문에 복수의 배열이 포함될수 있음으로 배열명과 동일한 _변수를 반드시 선언하는 식으로 많이들 하긴 했었다만.
이것을 좀더 나이스한 메타정보로 어찌해 볼 생각은 왜 못했을까 싶다.
![]() |
|---|
| GET, POST의 용법에 대해서도 다시 생각한다 |
물론 기본은 기본이지만 나는 대부분 GET과 POST로 모든것을 다 처리하고 있었는데 말이다.



