13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] OpenID Connect

  • [Cloud] OIDC와 SSO를 활용한 사내 인증 시스템 통합 전략 분석

    [Cloud] OIDC와 SSO를 활용한 사내 인증 시스템 통합 전략 분석

    안녕하세요, 13년차의 서버실 주인장입니다. 오늘은 인프라 엔지니어라면 한 번쯤은 고민하고, 또 삽질하게 되는 주제, 바로 OIDC(OpenID Connect)와 SSO(Single Sign-On)를 활용한 사내 인증 시스템 통합 전략에 대해 이야기해보려고 합니다. 사내에 시스템이 한두 개가 아닐 텐데, 매번 다른 아이디와 비밀번호로 로그인하는 게 여간 귀찮은 일이 아니죠. 저도 처음엔 ‘그냥 다 개별적으로 관리하면 되지 뭐’라고 안일하게 생각했었는데, 시스템이 늘어날수록 사용자들의 불만이 폭주하더라고요. ‘로그인만 수십 번 하는 것 같다’는 피드백을 들었을 때는 정말 등골이 오싹했었습니다. 😱

    이런 불편함을 해소하고 보안 강화는 물론, 사용자 경험 개선까지 동시에 잡을 수 있는 방법이 바로 SSO, 그리고 그 핵심에 있는 OIDC입니다. 저도 저희 회사 시스템들을 OIDC 기반으로 통합하면서 정말 많은 삽질을 했거든요. 오늘은 그 경험을 바탕으로 OIDC와 SSO가 무엇인지, 어떻게 통합해야 하는지, 그리고 어떤 문제들을 만날 수 있는지 솔직하게 풀어보겠습니다.

    OIDC SSO 사내 인증 시스템 통합 아키텍처 다이어그램

    OIDC와 SSO를 활용한 사내 인증 시스템 통합의 전체 아키텍처 다이어그램입니다. 사용자가 SSO 포털을 통해 OIDC Provider에 인증하고, 여러 서비스에 접근하는 흐름을 한눈에 볼 수 있습니다.

    SSO와 OIDC, 이 둘은 대체 뭘까요?

    먼저 핵심 개념들을 쉽고 명확하게 정리해 볼게요. 저도 처음엔 OAuth랑 OIDC가 뭐가 다른지 헷갈려서 엄청 찾아봤거든요. 간단히 정리해볼게요.

    SSO (Single Sign-On): 한 번의 로그인으로 만사형통!

    SSO(Single Sign-On, 싱글 사인온)는 말 그대로 한 번의 인증(로그인)으로 여러 개의 서로 다른 애플리케이션이나 서비스에 접근할 수 있도록 해주는 인증 방식입니다. 예를 들어, 회사 포털에 한 번 로그인하면 그룹웨어, 메신저, 인사 시스템 등 모든 사내 시스템에 추가 로그인 없이 바로 접근할 수 있는 거죠. 사용자 입장에서는 정말 편리하고, 관리자 입장에서는 사용자 계정 관리가 훨씬 수월해집니다. 💡

    OAuth 2.0 (Open Authorization): 권한 위임의 대명사

    OAuth 2.0(Open Authorization)은 인증(Authentication) 프로토콜이 아닙니다. 정확히는 권한 위임(Authorization Delegation)을 위한 프레임워크라고 보시면 됩니다. ‘나’라는 사용자가 ‘서비스 A’에게 ‘서비스 B’에 있는 내 정보에 접근할 수 있는 권한을 위임할 때 사용됩니다. “카카오톡으로 로그인”이나 “구글로 로그인” 버튼을 눌렀을 때, 서비스 제공자가 내 개인 정보에 접근할 권한을 얻는 과정이 바로 OAuth 2.0을 통해 이루어집니다. 중요한 건, OAuth 2.0은 ‘누가 로그인했는지(인증)’보다는 ‘무엇에 접근할 수 있는지(권한)’에 초점을 맞춘다는 거죠.

    OIDC (OpenID Connect): OAuth 2.0 위에서 동작하는 인증 프로토콜

    드디어 오늘의 주인공, OIDC(OpenID Connect)입니다. OIDC는 OAuth 2.0 프레임워크 위에서 동작하는 인증(Authentication) 계층입니다. OAuth 2.0이 권한 위임에 집중했다면, OIDC는 ‘로그인한 사용자가 누구인지’를 확인하는 데 집중합니다. 사용자 정보를 담은 ID Token(아이디 토큰)을 발행하여, 클라이언트 애플리케이션이 사용자를 식별하고 인증할 수 있도록 해줍니다. 즉, OAuth 2.0은 “문 열어줄 권한”을 주고, OIDC는 “문 열고 들어온 사람이 누구인지 신분증 확인”까지 해준다고 생각하시면 쉽습니다.

    OAuth 2.0 vs OIDC 비교

    특징 OAuth 2.0 OIDC (OpenID Connect)
    목적 권한 위임 (Authorization) 사용자 인증 (Authentication)
    기반 기술 인증/인가를 위한 프레임워크 OAuth 2.0 위에 구축된 프로토콜
    주요 토큰 Access Token (접근 토큰) ID Token (아이디 토큰), Access Token
    제공 정보 자원 접근 권한 사용자 신원 정보 (이름, 이메일 등)
    활용 예시 타사 앱에서 내 Google Drive 접근 Google, Kakao로 웹사이트 로그인

    OIDC는 OAuth 2.0의 유연한 구조를 활용하면서도, 표준화된 방식으로 사용자 인증 정보를 제공한다는 점에서 큰 장점이 있습니다.

    OIDC 기반 SSO, 실전 구현 삽질기

    자, 이제 개념은 잡혔으니 실제로 어떻게 사내 시스템에 OIDC SSO 통합을 적용했는지 이야기해 볼까요? 저는 주로 Keycloak 같은 오픈소스 OIDC Provider를 활용하는 편입니다. 홈랩에서도 자주 써봤거든요. 여기서는 OIDC Provider(Keycloak 등)가 이미 구축되어 있고, 우리가 만든 서비스(Client Application)에 연동하는 과정을 중심으로 설명하겠습니다.

    1단계: OIDC Provider에 클라이언트 등록

    가장 먼저 할 일은 OIDC Provider에 우리 서비스(Client Application)를 클라이언트(Client)로 등록하는 겁니다. 이때 몇 가지 중요한 정보를 입력해야 해요.

    • Client ID (클라이언트 ID): 우리 서비스를 식별하는 고유한 ID입니다.
    • Client Secret (클라이언트 시크릿): 클라이언트의 비밀 키로, 보안상 매우 중요합니다. 절대 외부에 노출되면 안 돼요!
    • Redirect URI (리다이렉트 URI): 인증이 성공했을 때 OIDC Provider가 사용자 에이전트(브라우저)를 다시 보낼 URL입니다. 이 URL은 정확해야 합니다. 제가 초반에 제일 삽질 많이 했던 부분이 이 리다이렉트 URI 오타나 불일치였어요. ⚠️
    • Scope (스코프): 클라이언트가 사용자 정보 중 어떤 항목에 접근할 권한을 요청할지 정의합니다. 최소한 openid 스코프는 필수입니다. 보통 profile, email 등도 함께 요청하죠.
    OIDC Provider 클라이언트 등록 설정 화면

    OIDC Provider(예: Keycloak)에 새로운 클라이언트를 등록하는 설정 화면입니다. Client ID, Client Secret, Redirect URI, Scope 등을 정확히 입력해야 합니다. 특히 Redirect URI는 오타 없이 정확하게 입력하는 것이 중요합니다.

    2단계: 서비스 애플리케이션에 OIDC 클라이언트 연동

    이제 우리 서비스 애플리케이션에서 OIDC Provider와 통신할 차례입니다. 저는 웹 서비스 앞단에 Nginx를 두고 OIDC 모듈을 연동하거나, 직접 애플리케이션 코드에 OIDC 클라이언트 라이브러리를 사용하는 방식을 선호합니다. 여기서는 Nginx를 이용한 간단한 연동 예시와 함께, OIDC 플로우의 핵심을 보여드릴게요.

    Nginx OIDC 모듈을 사용한 연동 예시

    Nginx를 리버스 프록시(Reverse Proxy)로 사용하고, nginx-auth-oidc 같은 모듈을 활용하면 애플리케이션 코드 수정 없이도 OIDC 인증을 붙일 수 있습니다. 정말 편리하더라고요.

    
    # nginx.conf 예시 (http 블록 내 server 블록)
    
    server {
        listen 80;
        server_name your.service.com;
    
        # OIDC 설정 블록
        location / {
            # OIDC Provider의 Well-Known Configuration 엔드포인트
            # 예: https://idp.example.com/auth/realms/your-realm/.well-known/openid-configuration
            auth_request /_oauth2_proxy_auth; # 이 경로는 실제 인증 프록시 엔드포인트와 맞춰야 합니다.
            error_page 401 = /_oauth2_proxy_auth; # 401 에러 발생 시 인증 프록시로 리다이렉트
    
            # 인증이 성공하면 애플리케이션으로 트래픽 전달
            proxy_pass http://your_backend_service;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    
        # OIDC 인증 프록시 설정 (이 부분은 실제 OIDC 모듈 설정에 따라 달라질 수 있습니다)
        location = /_oauth2_proxy_auth {
            internal; # 외부에서 직접 접근 불가
            proxy_pass http://localhost:PORT/auth; # 실제 OIDC 인증 프록시 서버 주소
            proxy_pass_request_body off;
            proxy_set_header Content-Length "";
            proxy_set_header X-Original-URI $request_uri;
            # 여기에 OIDC Client ID, Secret, Redirect URI 등의 환경 변수나 설정 파일 경로 지정
            # 예: proxy_set_header X-OIDC-Client-ID "your_client_id";
            # proxy_set_header X-OIDC-Client-Secret "your_client_secret";
            # proxy_set_header X-OIDC-Redirect-URI "https://your.service.com/oauth2/callback";
        }
    
        # OIDC 콜백 엔드포인트
        location = /oauth2/callback {
            proxy_pass http://localhost:PORT/callback; # OIDC 인증 프록시 콜백 엔드포인트
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    

    위 Nginx 설정은 개념적인 예시이며, 실제 nginx-auth-oidc 모듈이나 oauth2_proxy 같은 솔루션을 사용할 경우 설정 방식이 조금 다를 수 있습니다. 핵심은 사용자가 보호된 리소스에 접근하려 할 때, Nginx가 이를 가로채 OIDC Provider로 인증을 위임하고, 인증이 완료되면 원래 요청을 백엔드 서비스로 전달하는 흐름입니다.

    OIDC 플로우 간략 설명 (Authorization Code Flow 기준)

    1. 사용자가 보호된 리소스(예: your.service.com/dashboard)에 접근합니다.
    2. 서비스 애플리케이션(또는 Nginx 프록시)은 사용자가 인증되지 않았음을 감지하고, OIDC Provider의 Authorization Endpoint(인가 엔드포인트)로 사용자를 리다이렉트합니다. 이때 Client ID, Redirect URI, Scope 등을 쿼리 파라미터로 넘깁니다.
    3. 사용자는 OIDC Provider 로그인 페이지에서 아이디/비밀번호를 입력하여 인증합니다.
    4. 인증 성공 시, OIDC Provider는 미리 등록된 Redirect URI로 Authorization Code(인가 코드)를 포함하여 사용자를 다시 우리 서비스로 리다이렉트합니다.
    5. 우리 서비스는 받은 Authorization Code를 이용해 OIDC Provider의 Token Endpoint(토큰 엔드포인트)로 Access Token과 ID Token을 요청합니다. 이때 Client Secret도 함께 전송하여 클라이언트의 신원을 증명합니다.
    6. OIDC Provider는 Access Token과 ID Token을 발급해줍니다.
    7. 우리 서비스는 ID Token을 검증하여 사용자 신원을 확인하고, Access Token을 사용하여 필요한 경우 사용자 정보(Userinfo Endpoint)를 추가로 조회하거나, 다른 리소스에 접근할 수 있습니다.
    8. 사용자는 이제 서비스에 로그인된 상태가 됩니다. 🎉

    주의사항과 트러블슈팅: 삽질은 나의 힘!

    이런 시스템 통합 작업은 늘 예상치 못한 문제의 연속이더라고요. 제가 겪었던 대표적인 삽질 경험과 해결책을 공유합니다.

    • ⚠️ Redirect URI 불일치: OIDC Provider에 등록된 Redirect URI와 실제 요청하는 URI가 단 한 글자라도 다르면 인증 플로우가 진행되지 않습니다. 심지어 http와 https, 마지막 슬래시 / 유무까지 정확히 일치해야 합니다.

      해결책: OIDC Provider 설정 화면과 애플리케이션 코드/설정 파일을 꼼꼼히 대조하고, 브라우저 개발자 도구(F12)의 네트워크 탭에서 실제 리다이렉트되는 URL을 확인하며 디버깅하세요.

      
              # curl 명령어로 .well-known/openid-configuration 확인하여 정확한 endpoint 정보 파악
              curl -s https://idp.example.com/auth/realms/your-realm/.well-known/openid-configuration | jq .
              

      이 명령어를 통해 OIDC Provider가 제공하는 정확한 엔드포인트와 정보들을 확인할 수 있습니다. 특히 authorization_endpoint, token_endpoint, jwks_uri 등을 잘 봐야 합니다.

    • ⚠️ Scope/Claim 누락: 필요한 사용자 정보(예: 이메일, 이름)가 ID Token이나 Userinfo Endpoint에서 넘어오지 않을 때가 있습니다. 이는 보통 클라이언트 등록 시 요청하는 Scope(스코프)가 부족하거나, OIDC Provider에서 해당 Claim(클레임)을 발행하도록 설정되지 않았기 때문입니다.

      해결책: 클라이언트 등록 시 openid profile email 등 필요한 스코프를 모두 요청했는지 확인하고, OIDC Provider의 사용자 속성(User Attributes) 또는 클레임 매핑 설정을 확인하세요.

    • ⚠️ Token 검증 실패: ID Token의 Signature(서명) 검증에 실패하거나, 유효 기간(exp 클레임)이 만료된 토큰을 사용하는 경우가 있습니다. 이는 주로 OIDC Provider의 JWKS(JSON Web Key Set) 엔드포인트 설정 오류, 서버 시간 동기화 문제, 또는 토큰 캐싱 문제에서 발생합니다.

      해결책: OIDC Provider의 JWKS URI가 정확한지 확인하고, 애플리케이션 서버의 시간이 NTP 등으로 정확하게 동기화되어 있는지 확인하세요. 토큰을 캐싱한다면 만료 시간을 고려해야 합니다.

    • ⚠️ Client Secret 노출 위험: Client Secret은 정말 중요합니다. 절대 하드코딩하거나 Git 저장소에 올리면 안 돼요.

      해결책: 환경 변수(Environment Variable), HashiCorp Vault 같은 Secrets Management 솔루션, 또는 Kubernetes Secret 등을 활용하여 안전하게 관리해야 합니다.

      
              # 환경 변수로 Client Secret 설정 예시 (애플리케이션 실행 시)
              export OIDC_CLIENT_SECRET="your_very_secret_key"
              python your_app.py
              

      이런 방식으로 서버 시작 시에만 접근하도록 하는 것이 안전합니다.

    검증 및 결과 확인: 드디어 로그인 성공!

    위의 삽질들을 거쳐서 드디어 OIDC 기반 SSO가 정상적으로 동작하는 것을 확인했습니다. 보통 다음과 같은 방법으로 검증합니다.

    1. 서비스 접근 및 로그인 시도: 웹 브라우저로 서비스 URL에 접속했을 때, OIDC Provider의 로그인 페이지로 정확히 리다이렉트되는지 확인합니다.
    2. 로그인 후 서비스 접근: 로그인 성공 후, 서비스의 메인 페이지나 보호된 리소스에 정상적으로 접근되는지 확인합니다.
    3. ID Token 및 Access Token 내용 확인: 개발자 도구 또는 애플리케이션 로그를 통해 발급된 ID Token(JWT 형식)을 jwt.io 같은 사이트에서 디코딩하여, 사용자 정보(sub, name, email 등)가 올바르게 포함되어 있는지 확인합니다. Access Token은 불투명할 수 있지만, OIDC Provider의 Userinfo Endpoint를 통해 사용자 정보를 가져올 때 사용됩니다.
    4. 세션 관리 확인: 한 번 로그인하면 다른 사내 시스템(OIDC Client로 등록된)에 추가 로그인 없이 접근되는지 확인합니다.
    OIDC SSO 로그인 성공 및 JWT 토큰 디코딩 결과 화면

    OIDC 기반 SSO 로그인 성공 후, 사용자 정보가 표시되는 웹 애플리케이션 대시보드와 JWT 토큰 디코딩 결과 화면입니다. 토큰에 담긴 사용자 정보가 정확한지 확인하는 과정이 중요합니다.

    마무리: OIDC SSO, 선택이 아닌 필수

    OIDC와 SSO를 사내 시스템에 통합하는 과정은 결코 쉽지 않습니다. 저도 수많은 시행착오와 삽질을 거쳤고, 밤샘 디버깅도 여러 번 했거든요. 하지만 고생 끝에 낙이 온다고, 제대로 구축된 OIDC 기반 SSO는 사용자 경험 개선, 보안 강화, 그리고 중앙 집중식 계정 관리라는 세 마리 토끼를 동시에 잡을 수 있게 해줍니다.

    OIDC 기반 SSO 통합의 주요 장점

    장점 설명
    사용자 경험 개선 한 번 로그인으로 여러 시스템 접근, 로그인 피로도 감소
    보안 강화 중앙 집중식 인증으로 보안 정책 일관성 유지, 2FA(다단계 인증) 적용 용이
    관리 효율성 증대 계정 생성/삭제/관리의 단일화, 감사(Audit) 용이
    표준화된 프로토콜 다양한 서비스 및 솔루션과의 호환성 보장

    이러한 장점들은 OIDC 기반 SSO가 단순한 편의 기능을 넘어, 현대 IT 인프라에서 필수적인 요소가 되었음을 보여줍니다.

    OIDC SSO 통합 주요 장점 인포그래픽

    OIDC 기반 SSO의 주요 장점을 요약한 인포그래픽입니다. 사용자 경험 개선부터 보안 강화, 관리 효율성 증대까지 다양한 이점을 명확하게 보여줍니다.

    만약 여러분의 사내 시스템이 아직도 각자도생의 길을 걷고 있다면, 지금 바로 OIDC 기반 SSO 통합을 진지하게 고민해 보시길 강력히 권해드립니다. 처음엔 어렵겠지만, 장기적으로는 훨씬 더 견고하고 효율적인 인프라를 만들 수 있을 거예요. 다음번에는 OIDC와 연동하여 RBAC(Role-Based Access Control, 역할 기반 접근 제어)를 어떻게 구현하는지에 대한 경험담을 풀어볼까 합니다. 궁금하신 점이 있다면 언제든 댓글 남겨주세요! 😉

  • [보안] OAuth 2.0 보안 허점 파헤치기: 실제 공격 사례와 방어 전략

    [보안] OAuth 2.0 보안 허점 파헤치기: 실제 공격 사례와 방어 전략

    목차

    [보안] OAuth 2.0 보안 허점 파헤치기: 실제 공격 사례와 방어 전략

    서비스 로그인 붙이다 보면 OAuth 2.0 보안 이야기를 꼭 만나게 됩니다. 처음엔 그냥 소셜 로그인 한 번 붙이면 끝나는 줄 알았거든요. 근데 운영 환경으로 올라가고, 모바일 앱이 붙고, 리버스 프록시(Reverse Proxy, 역방향 프록시) 뒤에 애플리케이션이 숨어버리면 얘기가 완전히 달라집니다. 제가 홈랩과 사내 테스트 환경에서 직접 굴려보니, OAuth 공격은 거창한 제로데이보다도 설정 실수, 검증 누락, 토큰 저장 위치 같은 데서 시작되는 경우가 훨씬 많더라고요. 이번 글에서는 OAuth 2.0 보안을 실제 공격 흐름 중심으로 풀어보고, 현업에서 바로 적용할 수 있는 방어 전략까지 정리해보겠습니다.

    OAuth 2.0 보안 전체 흐름과 공격 지점을 보여주는 아키텍처 다이어그램

    OAuth 2.0 인증 흐름에서 사용자, 애플리케이션, 인증 서버, 리소스 서버 사이의 이동 경로와 주요 공격 지점을 한눈에 보여주는 다이어그램입니다.

    1. 왜 OAuth 2.0 보안이 자꾸 사고로 이어질까요

    쉽게 말해 OAuth 2.0은 비밀번호를 직접 주고받지 않고 권한을 위임하는 방식입니다. 문제는 구조가 유연한 만큼, 잘못 붙이면 공격자에게도 길을 열어준다는 점입니다. 특히 아래 세 가지가 자주 문제를 만듭니다.

    • Redirect URI(리다이렉트 URI) 검증이 느슨한 경우가 많더라고요
    • state 값 검증이 빠져 CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조)가 가능한 경우
    • Access Token(액세스 토큰)을 브라우저에 무방비로 저장하는 경우

    저도 예전에 테스트 앱 하나 만들면서 redirect URI를 와일드카드 비슷하게 처리했다가, “이거 설마 되겠어?” 했던 우회가 진짜 성립하는 걸 보고 식은땀 난 적이 있습니다. 드디어 됐다 싶었던 로그인 연동이, 보안 관점에서는 시작점이었던 거죠.

    2. OAuth 2.0 핵심 개념, 헷갈리는 부분만 딱 짚어보겠습니다

    OAuth 2.0 보안을 보려면 역할을 먼저 분리해서 봐야 합니다.

    구성 요소 역할 보안 포인트
    Resource Owner 사용자 피싱 페이지 유도 방지
    Client 웹/모바일 애플리케이션 state, PKCE, redirect URI 검증
    Authorization Server 인증 및 토큰 발급 정확한 클라이언트 검증
    Resource Server API 서버 토큰 검증과 권한 범위 확인

    여기서 중요한 포인트가 있습니다. 인증(Authentication, 본인 확인)과 인가(Authorization, 권한 부여)를 섞어 생각하면 설계가 꼬입니다. OAuth 2.0은 기본적으로 인가 프레임워크이고, 로그인은 보통 OpenID Connect(OIDC, 인증 레이어)를 함께 붙여 다룹니다. 이 차이를 놓치면 토큰을 너무 많은 곳에서 믿어버리게 되거든요.

    Authorization Code Flow와 PKCE를 기본값으로 봐야 하는 이유

    요즘은 Authorization Code Flow(인가 코드 흐름)에 PKCE(Proof Key for Code Exchange, 코드 교환용 증명 키)를 붙이는 구성이 사실상 기본입니다. 예전엔 Implicit Flow(암시적 흐름)도 많이 보였는데, 실제로 써보니까 브라우저 노출 면이 넓고 운영상 통제가 까다롭더라고요. 그래서 저는 브라우저 기반 앱도 가능하면 백엔드 연계나 BFF(Backend For Frontend, 프론트엔드 전용 백엔드) 구조를 함께 검토합니다.

    3. 실제 OAuth 공격 사례, 패턴으로 보면 훨씬 잘 보입니다

    특정 회사 사고를 끌어와 자극적으로 보기보다, 반복되는 공격 패턴으로 보는 게 실무에는 훨씬 도움이 되거든요. 아래 세 가지는 제가 테스트 환경에서 재현도 해봤고, 보안 리뷰 때도 정말 자주 보는 유형입니다.

    사례 1. state 누락으로 인한 로그인 CSRF

    애플리케이션이 인증 요청을 보낼 때 state를 만들지 않거나, 만들어도 응답에서 검증하지 않으면 공격자가 자기 계정으로 발급한 인가 응답을 피해자 세션에 주입할 수 있습니다. 겉으로는 로그인 성공처럼 보이는데, 실제로는 피해자가 공격자 계정에 연결된 상태가 되는 거죠.

    • 증상: 사용자가 모르는 계정으로 연결됨
    • 원인: state 생성 또는 검증 누락
    • 방어: 요청별 고유 state 생성, 서버 세션과 비교, 1회성 사용

    사례 2. Redirect URI 오검증으로 인가 코드 탈취

    이건 진짜 위험합니다. Redirect URI를 정확히 일치시키지 않고 접두어(prefix) 비교나 부분 문자열 비교로 처리하면, 공격자가 비슷한 주소를 만들어 인가 코드나 토큰을 가로챌 수 있습니다. 처음엔 “도메인만 같으면 괜찮지 않나” 싶었는데, 하위 경로나 쿼리 문자열까지 엮이면 생각보다 쉽게 틈이 생기더라고요.

    • 증상: 정상 로그인 후 공격자 페이지로 코드 전달
    • 원인: 느슨한 redirect URI 검증
    • 방어: 사전 등록된 URI와 정확히 일치 비교

    사례 3. PKCE 미적용으로 인가 코드 가로채기 위험

    특히 퍼블릭 클라이언트(public client)인 모바일 앱, SPA(Single Page Application, 단일 페이지 애플리케이션) 계열에서 PKCE가 없으면 코드가 중간에서 노출됐을 때 교환 방어가 어렵습니다. PKCE는 code_verifier와 code_challenge를 사용해서, 코드를 훔쳐도 토큰으로 못 바꾸게 막는 장치입니다.

    • 증상: 코드 탈취 후 토큰 교환 시도
    • 원인: PKCE 미적용
    • 방어: S256 기반 PKCE 강제
    OAuth 2.0 보안에서 state 누락과 redirect URI, PKCE 문제를 비교한 공격 흐름 이미지

    세 가지 대표적인 OAuth 공격 패턴이 어디서 시작되고 어느 지점에서 차단할 수 있는지 비교하는 흐름도입니다.

    4. 실전 구현: 안전한 OAuth 2.0 보안 체크포인트를 코드로 붙여보겠습니다

    여기서는 Python Flask(플라스크) 예시로 보겠습니다. 프레임워크는 달라도 핵심은 같습니다. state 검증, PKCE 적용, redirect URI 고정, 이 세 개는 기본값으로 가져가셔야 합니다.

    Step 1. state 값을 만들고 세션에 묶기

    1. 로그인 시작 시 난수 기반 state 생성
    2. 서버 세션 또는 안전한 저장소에 보관
    3. 콜백에서 반드시 동일성 검증
    import secrets
    from flask import Flask, redirect, request, session, abort
    from urllib.parse import urlencode
    
    app = Flask(__name__)
    app.secret_key = "replace-with-secure-secret"
    
    AUTHORIZATION_ENDPOINT = "https://auth.example.com/oauth2/authorize"
    CLIENT_ID = "demo-client"
    REDIRECT_URI = "https://app.example.com/callback"
    
    @app.route("/login")
    def login():
        state = secrets.token_urlsafe(32)
        session["oauth_state"] = state
    
        params = {
            "response_type": "code",
            "client_id": CLIENT_ID,
            "redirect_uri": REDIRECT_URI,
            "scope": "openid profile email",
            "state": state,
        }
        return redirect(f"{AUTHORIZATION_ENDPOINT}?{urlencode(params)}")
    
    @app.route("/callback")
    def callback():
        returned_state = request.args.get("state")
        expected_state = session.pop("oauth_state", None)
    
        if not returned_state or returned_state != expected_state:
            abort(400, "invalid state")
    
        code = request.args.get("code")
        if not code:
            abort(400, "missing code")
    
        return "state validation passed"
    

    이 코드는 단순하지만 중요합니다. 제가 직접 해보니 state를 검증하는 순간, 재현되던 로그인 CSRF 시나리오가 바로 막히더라고요.

    Step 2. PKCE 붙이기

    PKCE는 생각보다 어렵지 않습니다. code_verifier를 만들고, 그걸 SHA-256으로 해시해서 code_challenge를 보내면 됩니다.

    import base64
    import hashlib
    import secrets
    
    
    def generate_pkce_pair():
        code_verifier = secrets.token_urlsafe(64)
        digest = hashlib.sha256(code_verifier.encode("ascii")).digest()
        code_challenge = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii")
        return code_verifier, code_challenge
    
    code_verifier, code_challenge = generate_pkce_pair()
    session["code_verifier"] = code_verifier
    
    params = {
        "response_type": "code",
        "client_id": CLIENT_ID,
        "redirect_uri": REDIRECT_URI,
        "scope": "openid profile email",
        "state": session["oauth_state"],
        "code_challenge": code_challenge,
        "code_challenge_method": "S256",
    }
    

    토큰 교환 시에는 저장한 code_verifier를 함께 보내야 합니다. 이 부분 빠뜨리면 “분명 PKCE 넣었는데 왜 안 되지?” 하고 삽질 좀 하게 됩니다 ㅎㅎ

    Step 3. Redirect URI는 정확히 고정하기

    운영 환경에서 제일 많이 깨지는 부분이기도 합니다. 프록시 뒤에서 http로 인식하거나, path가 달라지거나, 포트가 틀어지면 인증 서버와 애플리케이션의 인식이 어긋납니다.

    oauth:
      client_id: demo-client
      redirect_uri: https://app.example.com/callback
      allowed_redirect_uris:
        - https://app.example.com/callback
    

    여기서 중요한 포인트! 부분 일치 금지, 와일드카드 지양, 환경별 URI 명확 분리입니다.

    Step 4. 로컬에서 공격 시나리오 점검하기

    제가 홈랩에서 자주 쓰는 방식은 curl로 콜백을 강제로 때려보는 겁니다. 최소한의 재현만 해도 어디서 검증이 빠졌는지 바로 보입니다.

    curl -i "https://app.example.com/callback?code=test-code&state=wrong-state"
    
    curl -i "https://app.example.com/callback?code=test-code"
    

    정상이라면 둘 다 거절돼야 합니다. 하나라도 통과하면 바로 수정해야 합니다.

    OAuth 2.0 보안 구현에서 state와 PKCE 설정을 설명하는 구성 이미지

    안전한 OAuth 클라이언트 구현에서 state, PKCE, redirect URI 고정이 각각 어디에 들어가는지 보여주는 구성 이미지입니다.

    5. OAuth 2.0 보안 운영 팁: 코드보다 설정에서 더 많이 무너집니다

    사실 OAuth 공격은 코드보다 운영 설정에서 더 자주 터집니다. 애플리케이션 보안 관점에서 특히 아래 항목은 꼭 챙기셔야 합니다.

    • Access Token 저장 위치: 브라우저의 localStorage는 XSS에 취약할 수 있으니 신중히 접근
    • HTTPS 강제: 토큰과 코드가 평문으로 흘러가면 끝입니다
    • Scope 최소화: 꼭 필요한 권한만 요청
    • 토큰 수명 짧게: 장기 유효 토큰은 사고 반경을 키웁니다
    • Refresh Token 보호: 서버 측 저장과 회전(rotation) 전략 검토
    • 로그 마스킹: 토큰, 인가 코드, 사용자 식별자 노출 금지

    이건 제가 정말 여러 번 봤는데요. 개발 편의 때문에 디버그 로그에 전체 콜백 URL을 남기면, 거기에 code나 token이 그대로 찍히는 경우가 있습니다. 테스트 때는 편한데, 운영에서는 그대로 사고 증거가 되더라고요.

    6. ⚠️ 트러블슈팅: 제가 실제로 자주 겪었던 문제들

    문제 1. 프록시 뒤에서 redirect URI가 http로 바뀌는 경우

    Nginx나 Ingress(인그레스, 외부 트래픽 진입점) 뒤에 둘 때 앱이 원래 스킴을 못 알아차리면 https:// 대신 http://로 redirect URI를 만들어버립니다.

    • 해결: X-Forwarded-Proto 신뢰 설정
    • 해결: 프레임워크별 proxy headers 설정 확인
    • 해결: 인증 서버 등록 URI와 앱 생성 URI를 동일하게 맞춤

    문제 2. state를 세션에 저장했는데 콜백에서 사라지는 경우

    도메인, 서브도메인, SameSite 쿠키 정책이 엮이면 세션이 유지되지 않을 수 있습니다. 저도 처음엔 코드만 의심했는데, 알고 보니 쿠키 속성이 문제였던 적이 많았습니다.

    • 해결: 세션 쿠키 도메인과 SameSite 정책 점검
    • 해결: 로드밸런서 환경에서 세션 일관성 확인
    • 해결: 다중 인스턴스면 중앙 세션 저장소 사용

    문제 3. 모바일 앱에서 PKCE는 넣었는데 교환 실패

    대부분은 code_verifier를 로그인 시작 시점과 토큰 교환 시점에 다르게 쓰거나, Base64 URL 인코딩 처리가 어긋난 경우였습니다.

    • 해결: 최초 생성한 code_verifier를 그대로 유지
    • 해결: code_challenge_method=S256 확인
    • 해결: URL-safe Base64 처리와 패딩 제거 확인

    7. 검증과 결과: 무엇을 통과해야 “안전하다”고 말할 수 있을까요

    보안은 느낌으로 끝내면 안 됩니다. 체크리스트로 검증해야 합니다. 저는 아래 항목을 통과해야 최소 기준은 넘겼다고 봅니다.

    1. state가 없거나 틀리면 콜백이 거절된다
    2. 등록되지 않은 redirect URI는 인증 서버에서 거절된다
    3. PKCE 없이 또는 잘못된 verifier로는 토큰 교환이 실패한다
    4. 토큰과 code가 애플리케이션 로그에 남지 않는다
    5. 브라우저 개발자 도구에서 민감한 토큰 노출 면이 최소화돼 있다
    6. 권한 범위(scope)가 필요한 수준으로 제한돼 있다

    이렇게 점검하고 나면 OAuth 2.0 보안이 훨씬 단단해집니다. 화려한 기능 추가는 없어 보여도, 실제로는 장애와 사고를 줄이는 가장 값진 작업이더라고요.

    OAuth 2.0 보안 검증 결과와 체크리스트를 보여주는 대시보드 이미지

    state 검증, PKCE, redirect URI 검사, 로그 마스킹 여부를 통과/실패로 시각화한 결과 이미지입니다.

    8. OAuth 공격 방어 전략 한눈에 정리

    공격 유형 주요 원인 방어 전략
    로그인 CSRF state 검증 누락 고유 state 생성, 세션 바인딩, 1회성 사용
    인가 코드 탈취 redirect URI 오검증 정확 일치 비교, 사전 등록 URI만 허용
    코드 재사용/가로채기 PKCE 미적용 S256 PKCE 강제
    토큰 유출 부적절한 저장/로그 출력 로그 마스킹, 저장 위치 최소화, HTTPS 강제
    과도한 권한 넓은 scope 요청 최소 권한 원칙 적용

    혹시 지금 운영 중인 서비스가 있다면, 위 표 기준으로 하나씩 점검해보세요. 특히 OAuth 2.0 보안은 한 군데만 잘한다고 끝나는 게 아니라, 클라이언트와 인증 서버, 프록시와 브라우저 저장소까지 같이 봐야 합니다.

    OAuth 2.0 보안 공격 유형과 방어 전략을 요약한 인포그래픽

    대표적인 OAuth 공격 유형과 대응책을 좌우 비교 형태로 정리한 인포그래픽입니다.

    9. 마무리: OAuth 2.0 보안은 기능이 아니라 운영 습관입니다

    정리해보면, OAuth 2.0 보안의 핵심은 복잡한 암호 기술보다도 기본기입니다. state 검증, PKCE 적용, redirect URI 정확 일치, 토큰 노출 최소화. 이 네 가지만 제대로 해도 공격면이 눈에 띄게 줄어듭니다. 저도 처음엔 문서만 보고 붙였다가 왜 자꾸 이상한 케이스가 생기나 했었는데, 결국 문제는 대부분 “설마 이 정도는 괜찮겠지”에서 시작됐습니다.

    다음 글에서는 OAuth와 함께 자주 등장하는 OpenID Connect(OIDC, 인증 레이어)의 ID Token 검증 포인트를 따로 다뤄볼 예정입니다. 이전 글에서 다룬 리버스 프록시와 쿠키 보안 설정을 함께 보시면 더 이해가 잘 되실 겁니다.

    FAQ. 자주 헷갈리는 질문

    Q1. SPA에서도 OAuth를 안전하게 쓸 수 있나요?

    가능합니다. 다만 PKCE를 기본으로 하고, 토큰 저장 전략과 XSS 대응을 같이 설계해야 합니다.

    Q2. state와 nonce는 같은 건가요?

    완전히 같지는 않습니다. state는 요청 위조 방지에, nonce는 주로 재생 공격 방지와 토큰 검증 맥락에서 쓰입니다.

    Q3. redirect URI를 여러 개 등록해도 괜찮나요?

    괜찮습니다. 다만 각각을 명시적으로 등록하고 정확히 일치 비교해야 합니다. 범용 패턴 허용은 조심하셔야 합니다.

  • [Cloud] GitHub Actions OIDC로 AWS 인증하기: 보안 강화 및 자격 증명 관리

    [Cloud] GitHub Actions OIDC로 AWS 인증하기: 보안 강화 및 자격 증명 관리

    GitHub Actions에서 AWS 인증, 아직도 IAM Access Key 쓰시나요?

    안녕하세요, 13년차 인프라 엔지니어이자 서버실 주인장입니다. 지난 몇 년간 수많은 CI/CD 파이프라인(Continuous Integration/Continuous Delivery Pipeline)을 구축하고 관리해왔는데, GitHub Actions와 AWS를 연동해서 사용하는 경우가 정말 많았거든요. 처음에는 저도 많은 분들처럼 AWS IAM(Identity and Access Management) 사용자의 Access Key와 Secret Key를 GitHub Secrets에 넣어 사용했습니다. 편리하긴 했죠. 근데 이게 뭔가 찜찜하더라고요.

    Access Key는 말 그대로 영구적인 자격 증명(Long-lived Credentials)이라 탈취 위험이 늘 존재하고, 정기적으로 Key를 교체(Rotation)해야 하는 관리 부담도 만만치 않았습니다. 만약 여러 레포지토리에서 같은 키를 쓴다면 더더욱 골치 아파지고요. 혹시 이런 경험 있으신가요? 저도 처음엔 이 방식밖에 없나 싶었는데, 다행히 더 안전하고 효율적인 방법이 등장했습니다. 바로 GitHub Actions OIDC(OpenID Connect)를 활용한 AWS 인증입니다! 오늘은 이 OIDC를 이용해 GitHub Actions에서 AWS에 안전하게 접근하는 방법을 제 경험을 바탕으로 자세히 알려드릴게요. CI/CD 파이프라인의 보안을 한 단계 끌어올리는 중요한 포인트가 될 겁니다.

    GitHub Actions OIDC를 이용한 AWS 인증의 전체적인 아키텍처 다이어그램입니다. GitHub Actions가 OIDC Provider 역할을 하고, AWS IAM이 이를 신뢰하여 임시 자격 증명을 발급하는 과정을 보여줍니다.

    OIDC(OpenID Connect)와 워크로드 아이덴티티(Workload Identity)가 뭔가요?

    본격적인 설정에 들어가기 전에, OIDC와 워크로드 아이덴티티라는 개념을 잠시 짚고 넘어가면 좋습니다. 복잡하게 들릴 수 있지만, 쉽게 말해볼게요.

    • OIDC (OpenID Connect, 오픈아이디 커넥트): OAuth 2.0 위에 구축된 인증(Authentication) 프로토콜입니다. 사용자(혹은 서비스)가 어떤 Identity Provider(신원 제공자)에게 “나 누구야”라고 인증받으면, Identity Provider는 ID Token이라는 걸 발급해줍니다. 이 토큰 안에는 “이 사람이 누구고, 어떤 방식으로 인증했는지” 같은 정보가 담겨있죠. AWS의 경우, GitHub Actions가 Identity Provider 역할을 하고, AWS IAM이 이 ID Token을 신뢰하는 Relying Party(의존 당사자)가 되는 겁니다.
    • 워크로드 아이덴티티 (Workload Identity): CI/CD 파이프라인의 워크로드(Workload)나 컨테이너처럼 사람이 아닌 시스템에 신원(Identity)을 부여하는 개념입니다. 기존의 Access Key 방식처럼 영구적인 자격 증명을 주지 않고, 필요할 때만 임시 자격 증명(Temporary Credentials)을 발급받아 사용하는 방식이에요. 이렇게 하면 자격 증명 탈취 위험을 최소화하고, 키 관리 부담을 없앨 수 있습니다.

    결론적으로, GitHub Actions OIDC를 사용하면 GitHub Actions 워크플로우가 직접 Access Key 없이 AWS에 “나 GitHub Actions의 이 레포지토리, 이 브랜치에서 실행된 애야!”라고 증명하고, AWS는 이 신원을 확인한 후 특정 권한을 가진 임시 자격 증명을 주는 방식이라고 이해하시면 됩니다. 진짜 편하고 안전하더라고요!

    GitHub Actions OIDC로 AWS 인증 설정 단계별 가이드

    자, 이제 실제로 GitHub Actions OIDC를 이용해 AWS에 인증하는 방법을 단계별로 따라해 볼까요? 제가 직접 해보니 몇 가지 포인트만 잘 기억하면 어렵지 않게 설정할 수 있었습니다.

    1단계: AWS IAM Identity Provider 생성하기

    가장 먼저 AWS IAM에서 GitHub Actions를 신뢰할 수 있는 OIDC Identity Provider로 등록해야 합니다. AWS 콘솔에서 진행하는 것이 가장 직관적입니다.

    1. AWS 콘솔에 로그인 후 IAM 서비스로 이동합니다.
    2. 왼쪽 탐색 메뉴에서 Access management (액세스 관리) > Identity Providers (자격 증명 공급자)를 클릭합니다.
    3. Add provider (공급자 추가) 버튼을 클릭합니다.
    4. Provider type (공급자 유형)으로 OpenID Connect를 선택합니다.
    5. Provider URL (공급자 URL)에 <code>https://token.actions.githubusercontent.com 을 입력합니다.
    6. Get thumbprint (지문 가져오기) 버튼을 클릭하여 서버 인증서 지문을 자동으로 가져옵니다.
    7. Audience (대상)에는 sts.amazonaws.com 을 입력하고 Add provider (공급자 추가)를 클릭하여 완료합니다.

    💡 팁: sts.amazonaws.com은 AWS Security Token Service의 기본 대상입니다. 다른 용도로 특정 서비스에만 OIDC를 사용한다면 해당 서비스의 Audience를 사용할 수도 있습니다.

    AWS IAM 콘솔에서 OIDC Identity Provider를 생성하는 화면입니다. Provider URL과 Audience를 정확히 입력하는 것이 중요합니다.

    2단계: AWS IAM Role 생성하기

    이제 이 OIDC Identity Provider를 통해 GitHub Actions가 임시 자격 증명을 요청할 수 있는 IAM Role을 생성해야 합니다. 이 역할에는 GitHub Actions가 AWS에서 수행할 작업에 대한 권한을 부여하게 됩니다.

    1. IAM 콘솔에서 Access management (액세스 관리) > Roles (역할)로 이동합니다.
    2. Create role (역할 생성) 버튼을 클릭합니다.
    3. Select type of trusted entity (신뢰할 수 있는 개체 유형 선택)에서 Custom trust policy (사용자 지정 신뢰 정책)를 선택합니다.
    4. 다음과 같이 신뢰 정책을 작성합니다. 여기서 StringEquals 조건이 핵심입니다!
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Federated": "arn:aws:iam::YOUR_AWS_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
          },
          "Action": "sts:AssumeRoleWithWebIdentity",
          "Condition": {
            "StringEquals": {
              "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
              "token.actions.githubusercontent.com:sub": "repo:YOUR_GITHUB_ORG/YOUR_GITHUB_REPO:ref:refs/heads/main"
            }
          }
        }
      ]
    }

    ⚠️ 주의사항:

    • YOUR_AWS_ACCOUNT_ID: 여러분의 AWS 계정 ID로 교체해야 합니다.
    • YOUR_GITHUB_ORG/YOUR_GITHUB_REPO: GitHub 조직(Organization) 이름과 레포지토리(Repository) 이름으로 교체해야 합니다.
    • ref:refs/heads/main: 이 부분은 특정 브랜치(Branch)에서만 역할 가정을 허용하겠다는 의미입니다. *를 사용하여 모든 브랜치를 허용할 수도 있지만, 보안을 위해 특정 브랜치를 지정하는 것을 권장합니다. 예를 들어, 특정 태그(tag)에서만 허용하려면 ref:refs/tags/v*와 같이 설정할 수 있습니다.
    1. 정책 검토 후 다음 단계로 넘어갑니다.
    2. 이 역할에 필요한 Permissions (권한)을 부여합니다. 예를 들어 S3 버킷에 파일을 업로드해야 한다면 AmazonS3FullAccess 대신 필요한 최소한의 권한(Least Privilege)을 부여하는 것이 좋습니다. 저는 테스트를 위해 AmazonS3ReadOnlyAccess를 잠시 붙여봤습니다.
    3. 역할 이름을 지정하고(예: GitHubActionsOIDC-S3AccessRole) 역할을 생성합니다.

    3단계: GitHub Actions Workflow 설정하기

    마지막으로 GitHub Actions 워크플로우 YAML 파일에 OIDC를 통한 AWS 인증 로직을 추가합니다. configure-aws-credentials 액션을 사용하면 아주 쉽게 설정할 수 있습니다.

    name: Deploy to AWS S3 via OIDC
    
    on:
      push:
        branches:
          - main
    
    permissions:
      id-token: write # OIDC ID Token을 요청하기 위해 필수
      contents: read # 레포지토리 코드 읽기 권한
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout code
            uses: actions/checkout@v4
    
          - name: Configure AWS Credentials with OIDC
            uses: aws-actions/configure-aws-credentials@v4
            with:
              role-to-assume: arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/GitHubActionsOIDC-S3AccessRole # 2단계에서 생성한 역할 ARN
              aws-region: ap-northeast-2 # 여러분의 AWS 리전
              # role-session-name: optional-session-name # (선택 사항)
    
          - name: List S3 buckets (for verification)
            run: aws s3 ls

    ⚠️ 여기서 중요한 포인트! permissions: id-token: write 설정은 반드시 필요합니다. 이 권한이 없으면 GitHub Actions가 OIDC ID Token을 생성할 수 없어 AWS 인증이 실패합니다. 처음엔 이걸 몰라서 삽질 좀 했습니다 ㅎㅎ

    삽질 경험: “AccessDenied” 에러의 늪에서 벗어나기 ⚠️

    제가 처음 GitHub Actions OIDC를 설정하면서 가장 많이 겪었던 문제는 다름 아닌 “AccessDenied” 에러였습니다. 워크플로우 로그를 보면 An error occurred (AccessDenied) when calling the AssumeRoleWithWebIdentity operation: Not authorized to perform sts:AssumeRoleWithWebIdentity 이런 메시지가 뜨더라고요. 진짜 답답했죠.

    주요 원인은 대부분 IAM Role의 Trust Policy (신뢰 정책) 조건 문제였습니다. 제가 겪었던 실수와 해결 방법은 다음과 같습니다.

    • Audience 불일치: IAM Identity Provider를 생성할 때 Audience를 sts.amazonaws.com으로 설정했는데, IAM Role Trust Policy의 "token.actions.githubusercontent.com:aud" 조건에도 정확히 "sts.amazonaws.com"이 들어가야 합니다. 한 글자라도 다르면 인증이 실패합니다.
    • sub 조건 오류: 가장 흔한 실수입니다. "token.actions.githubusercontent.com:sub" 조건에 지정된 GitHub 레포지토리, 브랜치 정보가 정확해야 합니다. 예를 들어, repo:YOUR_GITHUB_ORG/YOUR_GITHUB_REPO:ref:refs/heads/main 에서 오타가 있거나, 워크플로우가 실행되는 브랜치와 다르면 에러가 발생합니다. 저는 처음에 main 브랜치로 설정해놓고 develop 브랜치에서 테스트하다가 한참을 헤맸습니다.
    • permissions: id-token: write 누락: GitHub Actions 워크플로우 자체에 OIDC 토큰을 생성할 권한이 없어서 생기는 문제입니다. 이 한 줄 때문에 몇 시간을 날린 적도 있어요. 꼭 확인하세요!
    • AWS 계정 ID 또는 역할 ARN 오타: 기본적인 실수지만, 의외로 자주 발생합니다. ARN을 복사 붙여넣기 할 때 다시 한번 확인하는 습관을 들이세요.

    문제가 발생하면 AWS CloudTrail 로그를 확인하는 것이 가장 좋습니다. AssumeRoleWithWebIdentity 호출이 실패한 이유가 자세히 기록되어 있으니 꼭 살펴보세요. 삽질 끝에 드디어 성공했을 때의 그 쾌감이란! 진짜 이 맛에 엔지니어 하는 것 같아요.

    드디어 성공! OIDC로 안전하게 AWS 리소스 접근하기 🎉

    위에 설명드린 대로 모든 설정을 마치고 GitHub Actions 워크플로우를 실행하면, 아래와 같이 성공적으로 AWS 리소스에 접근하는 모습을 볼 수 있습니다.

    GitHub Actions 워크플로우가 성공적으로 AWS CLI 명령어를 실행하여 S3 버킷 목록을 가져오는 로그입니다. OIDC 기반 인증이 정상적으로 작동했음을 보여줍니다.

    워크플로우 로그를 보면 aws s3 ls 명령어가 문제없이 실행되고, S3 버킷 목록이 출력되는 것을 확인할 수 있습니다. 이제 더 이상 GitHub Secrets에 Access Key를 저장할 필요가 없어졌습니다! 🎉

    이 방식의 가장 큰 장점은 바로 단기 자격 증명(Short-lived Credentials)이라는 점입니다. GitHub Actions 워크플로우가 실행될 때만 임시 자격 증명을 발급받아 사용하고, 워크플로우가 끝나면 만료되죠. 덕분에 키 탈취로 인한 보안 위험이 현저히 줄어들고, 키 교체 주기를 관리할 필요도 없어졌습니다. 관리적인 측면에서도 엄청난 이득이라고 생각해요.

    OIDC, CI/CD 보안의 새로운 표준이 되다

    오늘은 GitHub Actions OIDC를 이용해 AWS에 안전하게 인증하는 방법을 자세히 알아봤습니다. 제가 직접 경험하며 얻은 삽질 경험과 해결 과정도 솔직하게 공유해 드렸는데요. 이 방식은 단순히 편리함을 넘어 CI/CD 파이프라인의 보안을 근본적으로 강화하는 핵심 기술이라고 생각합니다.

    기존의 Access Key 방식과 OIDC를 활용한 AWS 인증 방식의 주요 특징을 비교한 표입니다. 보안성, 관리 용이성 등 여러 측면에서 OIDC의 장점을 한눈에 보여줍니다.

    핵심 장점을 다시 정리해볼까요?

    • 보안 강화: 영구적인 Access Key 없이 임시 자격 증명 사용으로 탈취 위험 최소화.
    • 관리 용이성: Access Key 생성, 배포, 교체 등의 관리 부담 해소.
    • 정교한 권한 제어: 특정 레포지토리, 특정 브랜치, 특정 태그에서만 AWS 리소스 접근 허용 가능.
    • 감사 추적 용이: CloudTrail을 통해 어떤 GitHub Actions 워크플로우가 어떤 역할로 AWS에 접근했는지 명확하게 추적 가능.

    저도 홈랩에서 다양한 CI/CD 환경을 구성하면서 OIDC의 강력함을 몸소 체험하고 있습니다. 앞으로는 OIDC 기반의 워크로드 아이덴티티가 CI/CD 보안의 표준으로 자리매김할 것이라고 확신합니다. 혹시 아직 Access Key를 사용하고 계시다면, 이번 기회에 OIDC로 전환해 보시는 것을 강력히 추천합니다! 처음엔 조금 낯설 수 있지만, 한번 설정해두면 정말 든든하거든요.

    다음 글에서는 AWS S3에 정적 웹사이트를 배포하는 과정을 GitHub Actions OIDC와 함께 자동화하는 방법에 대해 다뤄볼까 합니다. 기대해주세요! 그럼 다음 글에서 만나요! 👋