# 안전하게 비밀 저장

소프트웨어 개발의 비밀과 이를 안전하게 관리하는 방법에 대해 알아봅니다.

## 비밀이란?

소프트웨어 개발에서 비밀은 시스템, 서비스, 데이터, API에 대한 액세스를 인증하거나 권한을 부여하는 데 사용되는 중요한 정보입니다. 예를 들면 다음과 같습니다.

* GitHub의 REST API와 같은 외부 서비스와 상호작용을 할 수 있는 **API 키** 및 **액세스 토큰**입니다. 또한 액세스 토큰을 사용하면 GitHub Actions와 같은 서비스에서 인증이 필요한 작업을 수행할 수 있으며, 이를 나중에 실험할 예정입니다.
* 로컬 및 외부 데이터베이스와 스토리지에 대한 액세스 권한을 부여하는 **데이터베이스 자격 증명** 입니다.
* 프라이빗 SSH 및 PGP 키와 같은 **프라이빗 키**는 다른 서버에 액세스하고 데이터를 암호화하는 데 사용할 수 있습니다.

비밀은 중요한 시스템을 포함하여 많은 액세스 권한을 제공하므로 **비밀을 안전하게** 유지하는 것이 왜 그렇게 중요한지 이해할 수 있습니다.

### 비밀이 노출되면 어떻게 될까요?

* 공격자는 비밀이 액세스할 수 있는 모든 항목에 **무단으로 액세스**할 수 있습니다.
* 해커는 중요한 사용자 데이터를 포함하여 **데이터**를 도용할 수 있습니다. 개인 정보 보호와 법적 파급 효과가 있을 수 있으며 사용자와 애플리케이션에 대한 신뢰에 해를 끼칠 수 있습니다.
* 해커가 클라우드 공급자 계정에서 권한 없는 워크로드를 실행하는 경우 노출된 비밀로 인해 **비용**이 발생할 수 있습니다.
* 해커는 노출된 비밀을 사용하여 서버를 삭제, 수정, 중단하여 **가동 중지 시간 및 데이터 손실**을 일으킬 수 있습니다.

비밀이 사용자에게 부여하는 모든 액세스와 기능, 해커가 수행할 수 있는 작업을 고려해 보세요. 예를 들어 personal access token 계정에 대한 GitHub이 노출된 경우 해커가 귀하로 가장하여 GitHub에 게시물을 올리고 변경할 수 있습니다.

## 비밀 관리 모범 사례

이러한 유형의 문제를 방지하려면 모범 사례를 따라 유출을 방지하고 비밀이 노출된 경우 피해를 제한하세요.

### **PoLP(최소 권한 원칙)** 을 따릅니다.

가능하면 비밀이 수행할 수 있는 작업을 제한하고 필요한 작업으로만 액세스할 수 있습니다. 예시:

* 비밀을 사용하여 데이터를 읽고 데이터를 변경하지 않는 경우 **읽기 전용**으로 지정합니다.
* 사용 중인 API에서 비밀을 특정 범위 또는 권한으로만 제한할 수 있는 경우 **필요한 범위나 권한**만 선택합니다. 예를 들어 GitHub 비밀에 대해서만 문제를 만들어야 하는 경우 비밀이 리포지토리 콘텐츠나 기타 항목에 액세스할 이유가 없습니다.
* 비밀이 공격자에게 해당 암호를 소유한 사용자 계정에 대한 모든 권한을 부여하는 경우 비밀의 소유권을 가져올 수 있는 **서비스 계정을 만드는 것이 좋습니다**.

### 애플리케이션에서 비밀 보호

* **비밀을 하드코딩하지 않습니다**. 항상 **환경 변수** 또는 플랫폼의 비밀 관리 도구(예: GitHub의 리포지토리 비밀)를 사용합니다.
* 다른 사람과 비밀을 공유해야 하는 경우 **암호 관리자**와 같은 전용 도구를 사용합니다. 메일이나 인스턴트 메시지를 통해 비밀을 보내지 않습니다.
* 가능하면 **만료 날짜**를 설정하고 **비밀을 정기적으로 교체**합니다. 이렇게 하면 이전 비밀이 악용될 위험이 줄어듭니다.
* 애플리케이션에서 로그를 생성하는 경우 **기록하기 전에 비밀이 수정되었는지** 확인합니다. 그러지 않으면 활성 비밀을 일반 텍스트 파일에 저장할 수 있습니다.

### 비밀이 노출될 경우 피해 제한

* 1초 동안만 노출되더라도 손상된 비밀을 고려하고 **즉시 비밀을 해지**합니다. 그런 다음, 새 비밀을 생성하고 안전하게 저장합니다.
* **활동 로그**에서 손상된 비밀과 관련된 의심스러운 활동이 있는지 확인합니다.
* 비밀이 어떻게 노출되었는지 고려하고 다시는 이런 일이 발생하지 않도록 프로세스를 변경합니다.

## GitHub가 비밀을 안전하게 유지하는 방법

비밀을 안전하게 유지하기 위해 수행할 수 있는 작업은 많지만 GitHub에서 비밀을 유지하는 데 도움이 되는 작업도 많습니다. 모든 사용자가 실수할 수 있으므로 실수로 비밀을 노출했을 때 포착할 수 있는 기능을 지원합니다.

* **푸시 보호**는 나중에 실험해 볼 기능으로, GitHub의 리포지토리에 비밀 푸시를 차단합니다.
* **비밀 검색**은 리포지토리를 검사하고 비밀을 검색할 때 경고를 만듭니다. 일부 비밀의 경우 비밀을 자동으로 해지하는 등의 조처를 할 수 있도록 공급자에게 알립니다.

## 비밀을 안전하게 저장하는 연습

이 연습에서는 personal access token을 만들고 안전하게 저장하여 GitHub Actions와 함께 사용할 수 있도록 합니다. 만들 작업은 이슈에 응답하는 간단한 워크플로입니다.

### 1. 연습 리포지토리 만들기

먼저 작업할 리포지토리를 만듭니다.
`new2code` 계정에는 신속하게 시작하는 데 사용할 수 있는 템플릿 리포지토리가 있습니다.

1. [새 리포지토리 페이지](https://github.com/new?template_owner=new2code\&template_name=secret-action)로 이동합니다. 이 링크를 클릭하면 `new2code` 계정의 템플릿이 미리 선택됩니다.
2. “Owner”에서 사용자 계정이 선택되어 있는지 확인합니다.
3. “Repository name” 필드에 `secret-action`을 입력하세요.
4. 설명 필드 아래에서 **Public**을 선택하여 리포지토리 표시 유형을 설정합니다.
5. **Create repository**(리포지토리 만들기)를 클릭합니다.

### 2. 더미 토큰을 커밋하기

모두가 실수를 하며, 코딩의 여정 중 언젠가는 무심코 비밀을 노출할 수도 있습니다. 이 연습에서는 트리거되는 경고에 익숙해지고 편안해질 수 있도록 의도적으로 **가짜 토큰**을 커밋합니다.

1. 방금 생성한 리포지토리로 이동합니다.

2. 파일 목록에서 `.github/workflows`를 클릭하여 YAML 워크플로 파일로 이동합니다.

3. 파일 목록에서 `comment.yml`을 클릭하여 워크플로 파일을 엽니다.

4. 워크플로 파일을 편집하려면 오른쪽 위에서 <svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-pencil" aria-label="Edit this file" role="img"><path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"></path></svg>을 클릭합니다.

5. 줄 13에서 따옴표 사이에 이 더미 토큰, `GH_TOKEN: ""`을 삽입합니다.

   ```text
   secret_scanning_ab85fc6f8d7638cf1c11da812da308d43_abcde
   ```

   최종 결과는 다음과 같아야 합니다.

   ```yaml
   GH_TOKEN: "secret_scanning_ab85fc6f8d7638cf1c11da812da308d43_abcde"
   ```

6. 변경 내용을 커밋하려면 오른쪽 위에서 **변경 내용 커밋...** 을 클릭한 다음, 대화 상자에서 **변경 내용 커밋**을 다시 클릭합니다.

7. 이제 "비밀번호 스캐닝이 13번 줄에서 GitHub 비밀번호 스캐닝 비밀을 발견했습니다"라는 푸시 보호 경고가 표시됩니다.

   ![커밋하려고 시도한 파일의 13번 줄에 대한 푸시 보호 경고의 스크린샷 “Cancel” 단추가 주황색 윤곽선으로 강조 표시됩니다.](/assets/images/help/security/push-protection-example.png)

   더미 토큰을 사용한 실험이 아니었다면, 토큰 공개까지 한 걸음 남았다는 경고가 표시되었을 것입니다. 경고에서 선택할 수 있는 옵션을 검토합니다.

8. 커밋을 중지하고 비밀을 노출하지 않도록 하려면 **Cancel**을 클릭합니다. 오른쪽 위에서 **Cancel changes**를 클릭한 다음, 메시지가 표시되면 저장되지 않은 변경 내용을 삭제합니다.

### 3. 실제 토큰 만들기

이제 모범적인 절차를 따라 해 보겠습니다. 먼저 사용자 대신 작업을 수행할 수 있는 personal access token을 만듭니다(만든 메모는 사용자 계정에서 나온 것으로 표시됨).

> \[!NOTE] 각 구성 단계에 대해 최소 권한 원칙을 따르는 방법을 확인합니다. 토큰은 필요한 만료 기간이 가장 짧고, 필요한 리포지토리에만 액세스할 수 있으며, 작동하는 데 필요한 최소 권한을 갖습니다.

1. [새 personal access token 페이지](https://github.com/settings/personal-access-tokens/new)로 이동합니다.
2. “Token name”에서 새 토큰에 이름을 지정합니다. “Action token”처럼 사용할 수 있습니다.
3. “Expiration”에서 “7 days”를 선택합니다.
4. “Repository access”에서 **Only select repositories**를 선택합니다.
5. “Select repositories” 드롭다운에서 이전에 만든 연습 리포지토리**만** 선택합니다.
6. “Permissions” 섹션에서 “Repository permissions”의 오른쪽에서 <svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-unfold" aria-label="Expand" role="img"><path d="m8.177.677 2.896 2.896a.25.25 0 0 1-.177.427H8.75v1.25a.75.75 0 0 1-1.5 0V4H5.104a.25.25 0 0 1-.177-.427L7.823.677a.25.25 0 0 1 .354 0ZM7.25 10.75a.75.75 0 0 1 1.5 0V12h2.146a.25.25 0 0 1 .177.427l-2.896 2.896a.25.25 0 0 1-.354 0l-2.896-2.896A.25.25 0 0 1 5.104 12H7.25v-1.25Zm-5-2a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM6 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 6 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM12 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 12 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5Z"></path></svg>를 클릭하여 가능한 모든 권한을 봅니다.
7. “Issues”로 아래로 스크롤하고 오른쪽 드롭다운에서 “Read and write”를 선택합니다.
8. 페이지 아래쪽에서 **Generate token**을 클릭합니다. 메시지가 표시되면 **Generate token**을 다시 클릭하여 확인합니다.

이 시점부터 결과 토큰을 안전하게 처리하는 것이 중요합니다. 곧 토큰을 사용할 예정이므로 잠시 클립보드에 복사할 수 있습니다.

### 4. 토큰을 안전하게 저장

이제 리포지토리에 새 토큰을 안전하게 저장할 수 있습니다.

1. 연습의 시작 부분에서 만든 리포지토리로 이동합니다.
2. 리포지토리 이름 아래에서 **<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-gear" aria-label="gear" role="img"><path d="M8 0a8.2 8.2 0 0 1 .701.031C9.444.095 9.99.645 10.16 1.29l.288 1.107c.018.066.079.158.212.224.231.114.454.243.668.386.123.082.233.09.299.071l1.103-.303c.644-.176 1.392.021 1.82.63.27.385.506.792.704 1.218.315.675.111 1.422-.364 1.891l-.814.806c-.049.048-.098.147-.088.294.016.257.016.515 0 .772-.01.147.038.246.088.294l.814.806c.475.469.679 1.216.364 1.891a7.977 7.977 0 0 1-.704 1.217c-.428.61-1.176.807-1.82.63l-1.102-.302c-.067-.019-.177-.011-.3.071a5.909 5.909 0 0 1-.668.386c-.133.066-.194.158-.211.224l-.29 1.106c-.168.646-.715 1.196-1.458 1.26a8.006 8.006 0 0 1-1.402 0c-.743-.064-1.289-.614-1.458-1.26l-.289-1.106c-.018-.066-.079-.158-.212-.224a5.738 5.738 0 0 1-.668-.386c-.123-.082-.233-.09-.299-.071l-1.103.303c-.644.176-1.392-.021-1.82-.63a8.12 8.12 0 0 1-.704-1.218c-.315-.675-.111-1.422.363-1.891l.815-.806c.05-.048.098-.147.088-.294a6.214 6.214 0 0 1 0-.772c.01-.147-.038-.246-.088-.294l-.815-.806C.635 6.045.431 5.298.746 4.623a7.92 7.92 0 0 1 .704-1.217c.428-.61 1.176-.807 1.82-.63l1.102.302c.067.019.177.011.3-.071.214-.143.437-.272.668-.386.133-.066.194-.158.211-.224l.29-1.106C6.009.645 6.556.095 7.299.03 7.53.01 7.764 0 8 0Zm-.571 1.525c-.036.003-.108.036-.137.146l-.289 1.105c-.147.561-.549.967-.998 1.189-.173.086-.34.183-.5.29-.417.278-.97.423-1.529.27l-1.103-.303c-.109-.03-.175.016-.195.045-.22.312-.412.644-.573.99-.014.031-.021.11.059.19l.815.806c.411.406.562.957.53 1.456a4.709 4.709 0 0 0 0 .582c.032.499-.119 1.05-.53 1.456l-.815.806c-.081.08-.073.159-.059.19.162.346.353.677.573.989.02.03.085.076.195.046l1.102-.303c.56-.153 1.113-.008 1.53.27.161.107.328.204.501.29.447.222.85.629.997 1.189l.289 1.105c.029.109.101.143.137.146a6.6 6.6 0 0 0 1.142 0c.036-.003.108-.036.137-.146l.289-1.105c.147-.561.549-.967.998-1.189.173-.086.34-.183.5-.29.417-.278.97-.423 1.529-.27l1.103.303c.109.029.175-.016.195-.045.22-.313.411-.644.573-.99.014-.031.021-.11-.059-.19l-.815-.806c-.411-.406-.562-.957-.53-1.456a4.709 4.709 0 0 0 0-.582c-.032-.499.119-1.05.53-1.456l.815-.806c.081-.08.073-.159.059-.19a6.464 6.464 0 0 0-.573-.989c-.02-.03-.085-.076-.195-.046l-1.102.303c-.56.153-1.113.008-1.53-.27a4.44 4.44 0 0 0-.501-.29c-.447-.222-.85-.629-.997-1.189l-.289-1.105c-.029-.11-.101-.143-.137-.146a6.6 6.6 0 0 0-1.142 0ZM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM9.5 8a1.5 1.5 0 1 0-3.001.001A1.5 1.5 0 0 0 9.5 8Z"></path></svg> Settings**를 클릭합니다. "설정" 탭이 표시되지 않으면 **<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-kebab-horizontal" aria-label="More" role="img"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg>** 드롭다운 메뉴를 선택한 다음 **설정**을 클릭합니다.

   ![탭을 보여 주는 리포지토리 헤더의 스크린샷. "설정" 탭이 진한 주황색 윤곽선으로 강조 표시됩니다.](/assets/images/help/repository/repo-actions-settings.png)
3. 사이드바의 "Security" 섹션에서 **<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-key-asterisk" aria-label="key-asterisk" role="img"><path d="M0 2.75A2.75 2.75 0 0 1 2.75 0h10.5A2.75 2.75 0 0 1 16 2.75v10.5A2.75 2.75 0 0 1 13.25 16H2.75A2.75 2.75 0 0 1 0 13.25ZM2.75 1.5c-.69 0-1.25.56-1.25 1.25v10.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25V2.75c0-.69-.56-1.25-1.25-1.25Z"></path><path d="M8 4a.75.75 0 0 1 .75.75V6.7l1.69-.975a.75.75 0 0 1 .75 1.3L9.5 8l1.69.976a.75.75 0 0 1-.75 1.298L8.75 9.3v1.951a.75.75 0 0 1-1.5 0V9.299l-1.69.976a.75.75 0 0 1-.75-1.3L6.5 8l-1.69-.975a.75.75 0 0 1 .75-1.3l1.69.976V4.75A.75.75 0 0 1 8 4Z"></path></svg> Secrets and variables**를 선택하고 **Actions**를 클릭합니다.
4. “Repository secrets”에서 **새 리포지토리 비밀**을 클릭합니다.
5. **Name** 필드에 비밀의 이름을 입력합니다. 이 연습에서는 `MY_TOKEN`를 사용합니다.
6. **Secret** 필드에 이전에 생성한 personal access token을 붙여 넣습니다.
7. **비밀 추가**를 클릭합니다.

이제 비밀이 안전하게 암호화되어 사용할 준비가 되었습니다!

### 작업에서 토큰을 참조하기

이제 YAML 워크플로 파일을 업데이트하여 토큰을 사용하고 작동하는지 테스트할 수 있습니다.

1. 리포지토리로 다시 이동합니다. 리포지토리의 설정에 있는 경우 리포지토리 이름 아래에서 **<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-code" aria-label="code" role="img"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg> Code**를 클릭할 수 있습니다.

2. 파일 목록에서 `.github/workflows`를 클릭하여 YAML 워크플로 파일로 이동합니다.

3. 파일 목록에서 `comment.yml`을 클릭하여 워크플로 파일을 엽니다.

4. 워크플로 파일 편집을 시작하려면 오른쪽 위에서 <svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-pencil" aria-label="Edit this file" role="img"><path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"></path></svg>을 클릭합니다.

5. 줄 13에서, `GH_TOKEN: ""`에서, 빈 따옴표를 `${{ secrets.MY_TOKEN }}`으로 바꿉니다. 앞에서 추가한 리포지토리 비밀을 참조하게 됩니다.

   ```yaml
   GH_TOKEN: ${{ secrets.MY_TOKEN }}
   ```

6. 변경 내용을 커밋하려면 오른쪽 위에서 **Commit changes...** 을 클릭합니다.

7. “Commit changes” 대화 상자에서 “Commit message”를 편집하여 변경 내용을 반영합니다. 예를 들어 “리포지토리 비밀을 사용하도록 워크플로 업데이트”를 입력할 수 있습니다.

8. "커밋을 `main` 브랜치에 직접 수행"이 선택되어 있는지 확인하세요.

9. **변경 내용 커밋**을 클릭합니다.

### 6. 토큰 및 워크플로 테스트

이제 모든 준비가 끝났습니다. 계속하여 워크플로를 테스트해 보겠습니다.

1. 리포지토리 이름 아래에서 **<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-issue-opened" aria-label="issue-opened" role="img"><path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path></svg> Issues**를 클릭합니다.

   ![리포지토리의 기본 페이지 스크린샷. 가로 탐색 모음에서 "문제" 레이블이 지정된 탭이 진한 주황색으로 표시됩니다.](/assets/images/help/repository/repo-tabs-issues-global-nav-update.png)
2. **새 문제**를 클릭합니다.
3. “Add a title”에서 원하는 제목을 입력할 수 있습니다.
4. “Add a description”의 텍스트 영역에 `Hello`를 입력합니다.
5. 텍스트 영역 아래에서 **Create**를 클릭합니다.

워크플로를 완료할 시간이 있으면 새 주석이 표시됩니다. 귀하의 토큰을 사용하고 있으므로 주석은 직접 작성하게 되며, 그에 대한 답례로 인사말이 포함됩니다.

## 다음 단계

비밀 검색 및 푸시 보호에 대한 자세한 내용은 GitHub Skills에서 [비밀 검사 소개 과정](https://github.com/skills/introduction-to-secret-scanning/tree/main)을 완료할 수 있습니다.

코드 보안의 또 다른 중요한 부분은 프로젝트에서 코드 취약성을 식별하고 패치하는 방법을 배우는 것입니다.
[첫 번째 코드 취약성 찾기 및 수정](/ko/get-started/learning-to-code/finding-and-fixing-your-first-code-vulnerability)을(를) 참조하세요.