
공개 리포지토리에 노출된 OpenAI 키 — API 액세스 위험
요약
OpenAI API 키 유출 위험을 방지하기 위해 '액세스 여권(Access Passport)'이라는 관리된 발급 방법론을 제안합니다. 키가 코드에 포함되기 전 프로젝트, 소유자, 한도 등 6가지 필수 필드를 정의하여 관리할 것을 권장합니다.
핵심 포인트
- 단순히 기술적으로 올바른 키를 생성하는 것과 관리된 액세스는 다름
- 키 유출 시 책임 소재와 비용 통제를 위한 관리 체계 필요
- 액세스 여권의 6가지 필드: 프로젝트, 목적, 소유자, 환경, 한도, 재검토 날짜
키는 그에 대한 질문에 단 하나도 답하지 않고도 1분 만에 발급될 수 있습니다. 바로 여기서 주요 위험이 시작됩니다. 위험은 유출되는 순간이 아니라, 팀 내에서 이 OpenAI 키가 어떤 프로젝트에 속해 있는지, 누가 책임자인지, 그리고 얼마만큼의 금액을 청구할 수 있는지 아무도 말할 수 없는 시점부터 이미 시작됩니다.
아래 내용은 이미 발생한 유출 사례에 대한 분석이 아니라, 관리된 발급(managed issuance) 방법론에 관한 것입니다. 즉, OpenAI API 키가 코드와 빌링(billing)에 포함되기 전에 반드시 충족해야 하는 6가지 검증 가능한 필드에 대해 다룹니다. 이 방법론의 뒤에는 OpenAI의 실제 메커니즘, 공개 리포지토리에 키가 실수로 게시되었을 때의 GitHub 동작 방식, 그리고 이 방법론이 해결할 수 없는 정직한 한계점이 자리 잡고 있습니다.
기술적으로 올바른 키가 왜 아직 관리된 액세스가 아닌가
흔히 하는 가정은 다음과 같습니다: 만약 OpenAI API 키가 개인 계정에서 필요한 권한과 함께 올바르게 생성되었다면, 이미 통제 하에 있는 것이다. 이러한 가정은 팀들을 잘못된 길로 인도합니다. 기술적으로 올바른 키와 관리된 액세스(managed access)는 서로 다른 상태입니다.
관리된 액세스란 모든 OpenAI 키에 대해 다음 다섯 가지 사실에 대해 빠르게 답할 수 있음을 의미합니다: 어떤 프로젝트에 속해 있는가, 왜 생성되었는가, 소유자는 누구인가, 어떤 환경에서 작동하는가, 그리고 지출 한도는 어디까지인가. 이러한 답변이 없는 키는 주인이 없는 소모성 자산으로 남게 됩니다. 즉, 돈은 쓰면서 누구의 것인지는 침묵하는 상태가 됩니다.
이는 OpenAI 키 자체에만 해당되는 것이 아닙니다. 이 다섯 가지 답변 없이 발급된 별도의 OpenAI API 키 역시 주인이 없는 소모성 자산일 뿐이며, provod.ai와 같은 러시아 결제 경로 키도 마찬가지입니다. 해당 키들은 OpenAI의 조건과는 별개로 동일한 식별 정보를 통해 생성됩니다. 러시아에서의 결제에 대해서는 아래에서 다시 다루겠습니다.
액세스 여권: 6가지 필드
액세스 여권 (Access Passport) — 이는 OpenAI나 GitHub의 문서에 기술된 객체가 아니라, 이 글에서 제안하는 방법론입니다. 어떠한 공식 출처에서도 이러한 엔티티를 언급하지 않습니다. 프로젝트(projects), 소유자(owners), 한도(limits)는 이 방법론이 기반으로 하는 실제 메커니즘이지만, 이 6가지 필드로 구성된 스키마(schema) 자체는 저자의 독창적인 아이디어입니다.
"openai api key를 어떻게 얻나요?" 또는 "openai 키를 어디서 가져오나요?"와 같은 질문을 던지기 전에, 먼저 이 6가지 필드를 채워야 합니다. 그래야 키를 획득하는 과정 자체가 조직적인 허점이 아닌, 하나의 기술적인 단계가 됩니다.
여권의 6가지 필드:
- 프로젝트 (Project): 키가 어떤 격리된 액세스 단위에 연결되어 있는가.
- 목적 (Purpose): 키가 왜 필요한지 한 줄로 요약.
- 소유자 (Owner): 키와 그 폐기(revocation)에 책임을 지는 사람.
- 환경 (Environment): staging 또는 production, dev 또는 CI.
- 한도 (Limit): 최대 지출액 및 요청 빈도.
- 재검토 날짜 (Review Date): 여권을 다시 검토해야 하는 시점.
이 방법론의 가설은 간단합니다. 키를 발급하기 전에 이 6가지 필드를 채운다면, 주인이 없거나 제한이 없는 키들은 첫 번째 요청이 발생하기도 전에 걸러질 것이라는 점입니다. 이는 측정된 사실이 아닌 가설입니다. 여권은 OpenAI나 GitHub의 제품이 아니기 때문에, 그들 모두 이 가설을 확인해주지 않습니다.
이 방법론의 비용 또한 명확합니다. 여권은 API를 처음 호출하기 전까지 관리(administration) 단계를 추가합니다. 팀은 액세스가 설명 가능한 목적과 한도 없이 방치되지 않도록 하기 위해, 설정에 소요되는 시간을 비용으로 지불하는 것입니다.
[
하나의 비밀, 여러 이름: 그것이 실제로 발급되는 곳
개발자들은 동일한 비밀(secret)을 서로 다른 이름으로 부르곤 하는데, 이는 단순히 유의어의 문제가 아닙니다. 지원 티켓(support tickets)에서 openai key, api key openai, api keys open ai, open ai key라고 불리는 것들은 대부분 sk- 접두사가 붙은 동일한 비밀을 의미하며, 바로 이 형식이 openai api key sk라는 검색어를 설명합니다. 러시아어에서도 동일한 비밀이 api ключ openai, api open ai ключ, open ai api ключ 또는 ключ api open ai 등으로 나타납니다. 검색어의 단어 순서가 저장된 객체를 바꾸지는 않으며, OpenAI 문서에서는 이러한 단어 순서의 변형 없이 오직 하나의 용어인 "API key"로 고정되어 있습니다.
발급 페이지는 단 하나입니다. OpenAI 개인 계정 내의 API keys 섹션이며, 이는 platform openai com api keys 또는 더 긴 형태인 platform openai com account api keys (OpenAI 문서 기준, 접속일 2026-07-18)로 참조됩니다. 전체 주소는 팀이 어떤 버전의 링크를 저장했느냐에 따라 https platform openai com api keys와 https platform openai com account api keys 두 가지 방식으로 나타나며, "open ai" 사이에 공백이 있는 경우 platform open ai api keys 또는 platform open ai com api keys로 동일한 섹션을 검색하게 됩니다. 코드 내에서 동일한 키는 기본 주소인 https api openai com v1, 즉 https://api.openai.com/v1과 함께 사용되며, 키 단독으로는 사용되지 않습니다.
key와 token은 별도로 구분해야 합니다. 일상적으로 open ai token, api token open ai, open ai api token, open ai token api는 일반적인 키와 동일한 비밀을 의미하지만, OpenAI 문서 자체에서 "토큰 (token)"이라는 용어는 보통 액세스 비밀이 아닌 부하 계산 단위(units of load)를 지칭합니다. 이 두 가지 의미를 혼용해서는 안 됩니다. "한도 (limit)" 항목은 키 자체가 아니라 부하 토큰(RPM, TPM 및 기타 단위)을 설명하기 때문입니다.
영어권 및 러시아어권의 "어떻게 얻나요 (how to get)"라는 질문 형식은 각 검색어 옵션마다 별도의 동작을 수행하는 것이 아니라, 프로젝트 내부에서의 단 한 번의 클릭으로 귀결됩니다. "api open ai 얻는 법 (how to get api open ai)", "open ai api 얻는 법 (how to get open ai api)", "openai api 키 얻는 법 (how to get api key from openai)"과 같은 표현들은 모두 동일한 경로를 설명합니다. 즉, 계정 전체에 대한 키를 생성하는 것이 아니라, 프로젝트를 선택하고 새로운 비밀 키 (secret key) 생성을 클릭하는 과정입니다. "open ai key 얻는 법 (how to get open ai key)", "open ai api key 얻는 법 (open ai api key how to get)", "api key open ai 얻는 법 (how to get api key open ai)", "open ai api key 얻는 법 (how to get open ai api key)"이라고 작성할 때도 마찬가지입니다. 화면은 동일하며, 검색어의 단어 순서만 다를 뿐입니다. 영어로 질문을 구성하는 팀들의 경우 "open ai get api", "get open ai key", "open ai get api key"와 같은 표현을 사용하는데, 이 역시 질문 언어만 다를 뿐 동일한 화면을 의미합니다.
"얻다 (get)"라는 단어를 앞으로 옮긴다고 해서 동작이 바뀌지는 않습니다. "open ai 키 얻기 (open ai get key)"와 "open ai api 키 얻기 (get api key open ai)"는 여전히 프로젝트 내부에서의 동일한 클릭을 의미하며, "openai api 키 얻기 (get api key openai)", "openai 키 얻기 (get openai key)", "openai api 얻기 (openai get api)", "open ai api 얻기 (open ai api get)" 등은 다른 화면이 아니라 다른 검색어에 맞춰 단어 순서만 바꾼 것일 뿐입니다. "open ai api 키 얻는 법 (how to get api key open ai)"이라는 표현 역시 동일한 답변으로 귀결됩니다.
"어디서 가져오나요 (where to get)"와 "어디서 찾나요 (where to find)"라는 질문도 유사한 단어들로 구성됩니다: "openai api key 어디서 가져오나요 (openai api key where to get)", "openai api key 어디서 가져오나요 (where to get openai api key)", "api open ai 어디서 가져오나요 (where to get api open ai)", "api open ai 키 어디서 가져오나요 (where to get api key open ai)", "api open ai 키 어디서 찾나요 (where to find api key open ai)". 이 모든 질문은 조직 (organization) 전체 페이지가 아닌 동일한 프로젝트 페이지로 연결됩니다. 왜냐하면 앞서 설명한 바와 같이, 개별적인 한도 (limit)와 액세스 권한 (access rights)은 바로 프로젝트 수준에서 설정되기 때문입니다.
OpenAI 프로젝트와 한도가 키를 제한하는 방식
이 패스포트(Passport)는 실제 메커니즘에 기반합니다. OpenAI 문서(접속일: 2026-07-18)에 따르면, API 액세스는 "프로젝트 (Projects)"를 통해 구성됩니다. 각 프로젝트는 고유한 소유자(owners)와 참여자(participants), 해당 프로젝트 내부에서만 유효한 고유 키(keys), 그리고 고유한 속도 제한(rate limits) 및 비용 제한(usage limits)을 가집니다. 이를 통해 하나의 조직 내에서 예를 들어 스테이징(staging) 환경을 프로덕션(production) 환경과 분리할 수 있습니다 (출처).
패스포트의 "프로젝트" 및 "소유자" 필드는 이 메커니즘에 직접적으로 대응됩니다. OpenAI 문서에 따르면, 프로젝트 소유자는 프로젝트가 호출할 수 있는 모델을 제한하고 자체적인 속도 및 비용 제한을 설정할 수 있습니다. 이는 조직 전체에 적용되는 공통 OpenAI API 키 대신, 단일 키의 피해 범위(radius of impact)를 좁히기 위해 문서화된 방식으로 사용되는 방법입니다.
제한(limits)과 관련하여 사고 분석 시간을 단축해 주는 기술적인 세부 사항이 있습니다. OpenAI의 속도 제한은 조직(organization)과 프로젝트(project)라는 두 가지 수준에서만 작동하며, 개별 사용자 수준에서는 절대 작동하지 않습니다. 제한은 RPM, TPM, RPD, TPD, IPM 등 여러 단위로 동시에 계산되며, 가장 먼저 초과된 단위가 적용됩니다 (출처). 패스포트의 "제한" 항목은 추상적인 합의가 아니라, 인터페이스에서 확인할 수 있는 구체적인 프로젝트 설정입니다.
코드 대신 환경 변수 사용
"환경" 항목은 하나의 습관을 통해 구현됩니다. OpenAI의 공식 권장 사항은 다음과 같습니다: OpenAI API 키를 소스 코드에 직접 삽입(hardcode)하거나 리포지토리에 커밋하지 말고, 환경 변수(통용되는 이름은 OPENAI_API_KEY) 또는 전용 비밀 관리자(secret manager)에 저장하십시오 (출처). 실제 적용 방식은 다음과 같습니다:
# Unix 계열 시스템
export OPENAI_API_KEY="sk-..."
...
여기서 OpenAI API 키를 사용하는 방법과 그 해결책이 담겨 있습니다: 키는 코드나 설정 파일 내부에 직접 작성하는 것이 아니라, 실행 시점에 환경 변수 (environment variable)를 통해 주입됩니다. 키는 코드 옆에 있는 파일에 저장되는 것이 아니라 환경으로부터 읽어옵니다. 이러한 습관이 결여되면 OpenAI API 키는 의도치 않은 유출의 가장 흔한 원인이 됩니다. 비밀값 (secret)을 설정 파일에 직접 복사하고, 그 설정 파일이 git add에 포함되면, 그 이후부터는 키 소유자의 통제 범위를 벗어나게 됩니다.

키가 결국 공개 리포지토리에 노출되었을 때 발생하는 일
패스워드(Passport)는 주인 없는 키가 될 확률을 낮춰주지만, 커밋 실수 자체를 없애지는 못합니다. 이후에 어떤 일이 벌어질지 정확히 아는 것이 유익한데, 왜냐하면 이에 대한 대응은 개발자 인터페이스 측에서 이루어지는 것이 아니기 때문입니다.
OpenAI는 2021년 6월부터 GitHub의 비밀값 스캐닝 (secret-scanning) 프로그램 파트너로 참여하고 있습니다. GitHub는 공개 리포지토리의 모든 커밋을 검사하여 OpenAI 키 패턴을 확인하며, 일치하는 항목이 발견되면 이를 OpenAI로 직접 전달합니다. 그러면 OpenAI는 몇 초 이내에 자동으로 키를 비활성화하고 소유자에게 알림을 보냅니다 (출처).
여기에 명확하지 않은 세부 사항이 하나 있습니다. GitHub 문서에 따르면, 파트너십을 통한 일치 항목이 발견될 경우 비밀값은 서명된 웹훅 (webhook)을 통해 제공업체로 전송되며, 해당 리포지토리 자체의 Security/alerts 탭에는 의도적으로 표시되지 않습니다 (출처). 즉, 유출 사실은 GitHub 인터페이스가 아니라 OpenAI에서 보낸 이메일을 통해 알게 되는 경우가 더 많습니다. 프로그램 규칙에 따라 토큰 발행자는 해당 비밀값을 "공개되었으며 침해된 것 (public and compromised)"으로 간주하고, 서명을 확인하며, 액세스 권한을 취소하고 사용자에게 통지해야 합니다 (출처). 이는 파트너의 호의가 아니라 계약상의 의무입니다.
OpenAI의 자체 지침 또한 침해(compromise)가 의심되는 경우에 대해 동일한 취지를 가지고 있습니다: API Keys 패널에서 즉시 키를 취소(revoke)하고, 새 키를 발급하며, 기존 키를 사용하던 모든 애플리케이션을 업데이트하십시오 (출처). 공식적인 로테이션(rotation) 기준은 달력이 아닌 유출 의심 여부입니다. OpenAI와 GitHub의 자료에는 "90일마다"와 같은 의무적인 주기(cadence)가 명시되어 있지 않으며, 해당 수치는 제3자의 블로그에서만 발견되므로 이를 OpenAI의 규칙으로 간주해서는 안 됩니다.

키를 발급할지 말지 결정하는 방법
결정을 위한 방법론을 정리합니다. 아래 표는 키를 실제 작업에 투입할지, 아니면 발급하지 않은 상태로 둘지를 결정하는 기준입니다. 규칙은 단 하나입니다: 빈 칸이 있는 항목은 "나중에 처리"가 아니라 "중단(stop)"을 의미합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기