diff --git a/content/ko/docs/concepts/configuration/secret.md b/content/ko/docs/concepts/configuration/secret.md index d27faddc20..6836870616 100644 --- a/content/ko/docs/concepts/configuration/secret.md +++ b/content/ko/docs/concepts/configuration/secret.md @@ -6,7 +6,8 @@ content_type: concept feature: title: 시크릿과 구성 관리 description: > - 사용자의 이미지를 다시 빌드하거나 스택 구성의 시크릿을 노출하지 않고 시크릿과 애플리케이션 구성을 배포하고 업데이트한다. + 사용자의 이미지를 다시 빌드하거나 스택 구성의 시크릿을 노출하지 않고 + 시크릿과 애플리케이션 구성을 배포하고 업데이트한다. weight: 30 --- @@ -22,7 +23,7 @@ weight: 30 시크릿은 시크릿을 사용하는 파드와 독립적으로 생성될 수 있기 때문에, 파드를 생성하고, 확인하고, 수정하는 워크플로우 동안 시크릿(그리고 데이터)이 노출되는 것에 대한 위험을 경감시킬 수 있다. 쿠버네티스 -및 클러스터에서 실행되는 애플리케이션은 기밀 데이터를 비휘발성 +및 클러스터에서 실행되는 애플리케이션은 비밀 데이터를 비휘발성 저장소에 쓰는 것을 피하는 것과 같이, 시크릿에 대해 추가 예방 조치를 취할 수도 있다. 시크릿은 {{< glossary_tooltip text="컨피그맵" term_id="configmap" >}}과 유사하지만 @@ -34,32 +35,76 @@ weight: 30 시크릿을 안전하게 사용하려면 최소한 다음의 단계를 따르는 것이 좋다. -1. 시크릿에 대한 [암호화 활성화](/docs/tasks/administer-cluster/encrypt-data/). -2. 시크릿의 데이터 읽기 및 쓰기(간접적인 방식 포함)를 제한하는 [RBAC 규칙](/ko/docs/reference/access-authn-authz/authorization/) - 활성화 또는 구성. -3. 적절한 경우, RBAC과 같은 메커니즘을 사용하여 새로운 시크릿을 생성하거나 기존 시크릿을 대체할 수 있는 주체(principal)들을 제한한다. +1. 시크릿에 대해 [저장된 데이터 암호화(Encryption at Rest)를 활성화](/docs/tasks/administer-cluster/encrypt-data/)한다. +1. 시크릿 읽기 및 쓰기를 제한하는 + [RBAC 규칙을 활성화 또는 구성](/ko/docs/reference/access-authn-authz/authorization/)한다. + 파드 생성 권한을 가진 사람은 암묵적으로 시크릿에 접근할 수 있음에 주의한다. +1. 적절한 경우, RBAC과 같은 메커니즘을 사용하여 새로운 시크릿을 생성하거나 + 기존 시크릿을 대체할 수 있는 주체(principal)들을 제한한다. {{< /caution >}} +더 자세한 것은 [시크릿을 위한 정보 보안(Information security)](#시크릿을-위한-정보-보안-information-security)을 참고한다. + -## 시크릿 개요 - -시크릿을 사용하려면, 파드가 시크릿을 참조해야 한다. -시크릿은 세 가지 방법으로 파드와 함께 사용할 수 있다. +## 시크릿의 사용 +파드가 시크릿을 사용하는 주요한 방법으로 다음의 세 가지가 있다. - 하나 이상의 컨테이너에 마운트된 {{< glossary_tooltip text="볼륨" term_id="volume" >}} 내의 - [파일](#시크릿을-파드의-파일로-사용하기)로써 사용. -- [컨테이너 환경 변수](#시크릿을-환경-변수로-사용하기)로써 사용. + [파일](#using-secrets-as-files-from-a-pod)로써 사용. +- [컨테이너 환경 변수](#시크릿을-환경-변수-형태로-사용하기)로써 사용. - 파드의 [이미지를 가져올 때 kubelet](#imagepullsecrets-사용하기)에 의해 사용. 쿠버네티스 컨트롤 플레인 또한 시크릿을 사용한다. 예를 들어, [부트스트랩 토큰 시크릿](#부트스트랩-토큰-시크릿)은 노드 등록을 자동화하는 데 도움을 주는 메커니즘이다. +### 시크릿의 대체품 + +기밀 데이터를 보호하기 위해 시크릿 대신 다음의 대안 중 하나를 고를 수 있다. + +다음과 같은 대안이 존재한다. + +- 클라우드 네이티브 구성 요소가 + 동일 쿠버네티스 클러스터 안에 있는 다른 애플리케이션에 인증해야 하는 경우, + [서비스어카운트(ServiceAccount)](/docs/reference/access-authn-authz/authentication/#service-account-tokens) 및 + 그의 토큰을 이용하여 클라이언트를 식별할 수 있다. +- 비밀 정보 관리 기능을 제공하는 써드파티 도구를 + 클러스터 내부 또는 외부에 실행할 수 있다. + 예를 들어, 클라이언트가 올바르게 인증했을 때에만(예: 서비스어카운트 토큰으로 인증) 비밀 정보를 공개하고, + 파드가 HTTPS를 통해서만 접근하도록 처리하는 서비스가 있을 수 있다. +- 인증을 위해, X.509 인증서를 위한 커스텀 인증자(signer)를 구현하고, + [CertificateSigningRequests](/docs/reference/access-authn-authz/certificate-signing-requests/)를 사용하여 + 해당 커스텀 인증자가 인증서를 필요로 하는 파드에 인증서를 발급하도록 할 수 있다. +- [장치 플러그인](/ko/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/)을 사용하여 + 노드에 있는 암호화 하드웨어를 특정 파드에 노출할 수 있다. + 예를 들어, 신뢰할 수 있는 파드를 별도로 구성된 TPM(Trusted Platform Module, 신뢰할 수 있는 플랫폼 모듈)을 제공하는 노드에 스케줄링할 수 있다. + +위의 옵션들 및 시크릿 오브젝트 자체를 이용하는 옵션 중 2가지 이상을 조합하여 사용할 수도 있다. + +예시: 외부 서비스에서 단기 유효(short-lived) 세션 토큰을 가져오는 +{{< glossary_tooltip text="오퍼레이터" term_id="operator-pattern" >}}를 구현(또는 배포)한 다음, +이 단기 유효 세션 토큰을 기반으로 시크릿을 생성할 수 있다. +클러스터의 파드는 이 세션 토큰을 활용할 수 있으며, 오퍼레이터는 토큰이 유효한지 검증해 준다. +이러한 분리 구조는 곧 파드가 이러한 세션 토큰의 발급 및 갱신에 대한 정확한 메커니즘을 모르게 하면서도 파드를 실행할 수 있음을 의미한다. + +## 시크릿 다루기 + +### 시크릿 생성하기 + +시크릿 생성에는 다음과 같은 방법이 있다. + +- [`kubectl` 명령으로 시크릿 생성](/ko/docs/tasks/configmap-secret/managing-secret-using-kubectl/) +- [환경 설정 파일을 사용하여 시크릿 생성](/ko/docs/tasks/configmap-secret/managing-secret-using-config-file/) +- [kustomize를 사용하여 시크릿 생성](/ko/docs/tasks/configmap-secret/managing-secret-using-kustomize/) + +#### 시크릿 이름 및 데이터에 대한 제약 사항 {#restriction-names-data} + 시크릿 오브젝트의 이름은 유효한 [DNS 서브도메인 이름](/ko/docs/concepts/overview/working-with-objects/names/#dns-서브도메인-이름)이어야 한다. + 사용자는 시크릿을 위한 파일을 구성할 때 `data` 및 (또는) `stringData` 필드를 명시할 수 있다. 해당 `data` 와 `stringData` 필드는 선택적으로 명시할 수 있다. `data` 필드의 모든 키(key)에 해당하는 값(value)은 base64로 인코딩된 문자열이어야 한다. @@ -72,6 +117,717 @@ weight: 30 있으면, `stringData` 필드에 지정된 값이 우선적으로 사용된다. +#### 크기 제한 {#restriction-data-size} + +개별 시크릿의 크기는 1 MiB로 제한된다. +이는 API 서버 및 kubelet 메모리를 고갈시킬 수 있는 매우 큰 시크릿의 생성을 방지하기 위함이다. +그러나, 작은 크기의 시크릿을 많이 만드는 것도 메모리를 고갈시킬 수 있다. +[리소스 쿼터](/ko/docs/concepts/policy/resource-quotas/)를 사용하여 +한 네임스페이스의 시크릿 (또는 다른 리소스) 수를 제한할 수 있다. + +### 시크릿 편집하기 + +kubectl을 사용하여 기존 시크릿을 편집할 수 있다. + +```shell +kubectl edit secrets mysecret +``` + +이렇게 하면 기본으로 설정된 에디터가 열리며, +다음과 같이 `data` 필드에 base64로 인코딩된 시크릿 값을 업데이트할 수 있다. + +```yaml +# 아래 오브젝트를 수정한다. '#'로 시작하는 줄은 무시되고, +# 빈 파일을 저장하면 편집이 취소된다. 이 파일을 저장하는 도중에 오류가 발생하면 +# 관련 오류와 함께 파일이 다시 열릴 것이다. +# +apiVersion: v1 +data: + username: YWRtaW4= + password: MWYyZDFlMmU2N2Rm +kind: Secret +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: { ... } + creationTimestamp: 2020-01-22T18:41:56Z + name: mysecret + namespace: default + resourceVersion: "164619" + uid: cfee02d6-c137-11e5-8d73-42010af00002 +type: Opaque +``` + +위의 예시 매니페스트는 `data`에 `username` 및 `password` 2개의 키를 갖는 시크릿을 정의한다. +매니페스트에서 이 값들은 Base64 문자열이지만, +이 시크릿을 파드에 대해 사용할 때에는 kubelet이 파드와 컨테이너에 _디코드된_ 데이터를 제공한다. + +한 시크릿에 여러 키 및 값을 넣을 수도 있고, 여러 시크릿으로 정의할 수도 있으며, 둘 중 편리한 쪽을 고르면 된다. + +### 시크릿 사용하기 + +시크릿은 데이터 볼륨으로 마운트되거나 파드의 컨테이너에서 사용할 +{{< glossary_tooltip text="환경 변수" term_id="container-env-variables" >}}로 +노출될 수 있다. 또한, 시크릿은 파드에 직접 노출되지 않고, +시스템의 다른 부분에서도 사용할 수 있다. 예를 들어, 시크릿은 +시스템의 다른 부분이 사용자를 대신해서 외부 시스템과 상호 작용하는 데 사용해야 하는 +자격 증명을 보유할 수 있다. + +특정된 오브젝트 참조(reference)가 실제로 시크릿 유형의 오브젝트를 가리키는지 확인하기 위해, +시크릿 볼륨 소스의 유효성이 검사된다. +따라서, 시크릿은 자신에 의존하는 파드보다 먼저 생성되어야 한다. + +시크릿을 가져올 수 없는 경우 +(아마도 시크릿이 존재하지 않거나, 또는 API 서버에 대한 일시적인 연결 불가로 인해) +kubelet은 해당 파드 실행을 주기적으로 재시도한다. +kubelet은 또한 시크릿을 가져올 수 없는 문제에 대한 세부 정보를 포함하여 해당 파드에 대한 이벤트를 보고한다. + +#### 선택적 시크릿 {#restriction-secret-must-exist} + +시크릿을 기반으로 컨테이너 환경 변수를 정의하는 경우, +이 환경 변수를 _선택 사항_ 으로 표시할 수 있다. +기본적으로는 시크릿은 필수 사항이다. + +모든 필수 시크릿이 사용 가능해지기 전에는 +파드의 컨테이너가 시작되지 않을 것이다. + +파드가 시크릿의 특정 키를 참조하고, 해당 시크릿이 존재하지만 해당 키가 존재하지 않는 경우, +파드는 시작 과정에서 실패한다. + +### 파드에서 시크릿을 파일처럼 사용하기 {#using-secrets-as-files-from-a-pod} + +파드 안에서 시크릿의 데이터에 접근하고 싶다면, 한 가지 방법은 +쿠버네티스로 하여금 해당 시크릿의 값을 +파드의 하나 이상의 컨테이너의 파일시스템 내에 파일 형태로 표시하도록 만드는 것이다. + +이렇게 구성하려면, 다음을 수행한다. + +1. 시크릿을 생성하거나 기존 시크릿을 사용한다. 여러 파드가 동일한 시크릿을 참조할 수 있다. +1. `.spec.volumes[].` 아래에 볼륨을 추가하려면 파드 정의를 수정한다. 볼륨의 이름을 뭐든지 지정하고, 시크릿 오브젝트의 이름과 동일한 `.spec.volumes[].secret.secretName` 필드를 생성한다. +1. 시크릿이 필요한 각 컨테이너에 `.spec.containers[].volumeMounts[]` 를 추가한다. 시크릿을 표시하려는 사용되지 않은 디렉터리 이름에 `.spec.containers[].volumeMounts[].readOnly = true` 와 `.spec.containers[].volumeMounts[].mountPath` 를 지정한다. +1. 프로그램이 해당 디렉터리에서 파일을 찾도록 이미지 또는 커맨드 라인을 수정한다. 시크릿 `data` 맵의 각 키는 `mountPath` 아래의 파일명이 된다. + +다음은 볼륨에 `mysecret`이라는 시크릿을 마운트하는 파드의 예시이다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret + optional: false # 기본값임; "mysecret" 은 반드시 존재해야 함 +``` + +사용하려는 각 시크릿은 `.spec.volumes` 에서 참조해야 한다. + +파드에 여러 컨테이너가 있는 경우, 모든 컨테이너는 +자체 `volumeMounts` 블록이 필요하지만, 시크릿에 대해서는 시크릿당 하나의 `.spec.volumes` 만 필요하다. + +{{< note >}} +쿠버네티스 v1.22 이전 버전은 쿠버네티스 API에 접근하기 위한 크리덴셜을 자동으로 생성했다. +이러한 예전 메커니즘은 토큰 시크릿 생성 및 이를 실행 중인 파드에 마운트하는 절차에 기반했다. +쿠버네티스 v{{< skew currentVersion >}} 버전을 포함한 최근 버전에서는, +API 크리덴셜이 [TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/) API를 사용하여 직접 얻어지고, +[프로젝티드 볼륨](/ko/docs/reference/access-authn-authz/service-accounts-admin/#바인딩된-서비스-어카운트-토큰-볼륨)을 +사용하여 파드 내에 마운트된다. +이러한 방법을 사용하여 얻은 토큰은 수명이 제한되어 있으며, +토큰이 탑재된 파드가 삭제되면 자동으로 무효화된다. + +여전히 서비스 어카운트 토큰 시크릿을 [수동으로 생성](/docs/tasks/configure-pod-container/configure-service-account/#manually-create-a-service-account-api-token)할 수도 있다. +예를 들어, 영원히 만료되지 않는 토큰이 필요한 경우에 활용할 수 있다. +그러나, 이렇게 하기보다는 API 접근에 필요한 토큰을 얻기 위해 +[TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/) 서브리소스를 사용하는 것을 권장한다. +{{< /note >}} + +#### 특정 경로에 대한 시크릿 키 투영하기 + +시크릿 키가 투영되는 볼륨 내 경로를 제어할 수도 있다. +`.spec.volumes[].secret.items` 필드를 사용하여 각 키의 대상 경로를 변경할 수 있다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret + items: + - key: username + path: my-group/my-username +``` + +다음과 같은 일들이 일어날 것이다. + +* `mysecret`의 `username` 키는 컨테이너의 `/etc/foo/username` 경로 대신 + `/etc/foo/my-group/my-username` 경로에서 사용 가능하다. +* 시크릿 오브젝트의 `password` 키는 투영되지 않는다. + +`.spec.volumes[].secret.items` 를 사용하면, `items` 에 지정된 키만 투영된다. +시크릿의 모든 키를 사용하려면, 모든 키가 `items` 필드에 나열되어야 한다. + +키를 명시적으로 나열했다면, 나열된 모든 키가 해당 시크릿에 존재해야 한다. +그렇지 않으면, 볼륨이 생성되지 않는다. + +#### 시크릿 파일 퍼미션 + +단일 시크릿 키에 대한 POSIX 파일 접근 퍼미션 비트를 설정할 수 있다. +만약 사용자가 퍼미션을 지정하지 않는다면, 기본적으로 `0644` 가 사용된다. +전체 시크릿 볼륨에 대한 기본 모드를 설정하고 필요한 경우 키별로 오버라이드할 수도 있다. + +예를 들어, 다음과 같은 기본 모드를 지정할 수 있다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + volumes: + - name: foo + secret: + secretName: mysecret + defaultMode: 0400 +``` + +시크릿이 `/etc/foo` 에 마운트되고, +시크릿 볼륨 마운트로 생성된 모든 파일의 퍼미션은 `0400` 이다. + + +{{< note >}} +JSON을 사용하여 파드 또는 파드 템플릿을 정의하는 경우, +JSON 스펙은 8진수 표기법을 지원하지 않음에 유의한다. +`defaultMode` 값으로 대신 10진수를 사용할 수 있다(예를 들어, 8진수 0400은 10진수로는 256이다). +YAML로 작성하는 경우, `defaultMode` 값을 8진수로 표기할 수 있다. +{{< /note >}} + +#### 볼륨으로부터 시크릿 값 사용하기 + +시크릿 볼륨을 마운트하는 컨테이너 내부에서, 시크릿 키는 파일 형태로 나타난다. +시크릿 값은 base64로 디코딩되어 이러한 파일 내에 저장된다. + +다음은 위 예시의 컨테이너 내부에서 실행된 명령의 결과이다. + +```shell +ls /etc/foo/ +``` + +출력 결과는 다음과 비슷하다. + +``` +username +password +``` + +```shell +cat /etc/foo/username +``` + +출력 결과는 다음과 비슷하다. + +``` +admin +``` + +```shell +cat /etc/foo/password +``` + +출력 결과는 다음과 비슷하다. + +``` +1f2d1e2e67df +``` + +컨테이너의 프로그램은 필요에 따라 +이러한 파일에서 시크릿 데이터를 읽는다. + +#### 마운트된 시크릿은 자동으로 업데이트됨 + +볼륨이 시크릿의 데이터를 포함하고 있는 상태에서 시크릿이 업데이트되면, 쿠버네티스는 이를 추적하고 +최종적으로 일관된(eventually-consistent) 접근 방식을 사용하여 볼륨 안의 데이터를 업데이트한다. + +{{< note >}} +시크릿을 [subPath](/ko/docs/concepts/storage/volumes/#subpath-사용하기) +볼륨 마운트로 사용하는 컨테이너는 자동 시크릿 업데이트를 +받지 못한다. +{{< /note >}} + +kubelet은 해당 노드의 파드의 볼륨에서 사용되는 시크릿의 현재 키 및 값 캐시를 유지한다. +kubelet이 캐시된 값에서 변경 사항을 감지하는 방식을 변경할 수 있다. +[kubelet 환경 설정](/docs/reference/config-api/kubelet-config.v1beta1/)의 `configMapAndSecretChangeDetectionStrategy` 필드는 +kubelet이 사용하는 전략을 제어한다. 기본 전략은 `Watch`이다. + +시크릿 업데이트는 TTL(time-to-live)이 설정된 캐시 기반의 +API 감시(watch) 메커니즘에 의해 전파되거나 (기본값임), +각 kubelet 동기화 때마다 클러스터 API 서버로부터의 폴링으로 달성될 수 있다. + +결과적으로 시크릿이 업데이트되는 순간부터 +새 키가 파드에 투영되는 순간까지의 총 지연은 +kubelet 동기화 기간 + 캐시 전파 지연만큼 길어질 수 있다. +여기서 캐시 전파 지연은 선택한 캐시 유형에 따라 다르다(이전 단락과 동일한 순서로 나열하면, +감시(watch) 전파 지연, 설정된 캐시 TTL, 또는 직접 폴링의 경우 0임). + +### 시크릿을 환경 변수 형태로 사용하기 + +파드에서 {{< glossary_tooltip text="환경 변수" term_id="container-env-variables" >}} 형태로 +시크릿을 사용하려면 다음과 같이 한다. + +1. 시크릿을 생성(하거나 기존 시크릿을 사용)한다. 여러 파드가 동일한 시크릿을 참조할 수 있다. +1. 사용하려는 각 시크릿 키에 대한 환경 변수를 추가하려면 + 시크릿 키 값을 사용하려는 각 컨테이너에서 파드 정의를 수정한다. + 시크릿 키를 사용하는 환경 변수는 시크릿의 이름과 키를 `env[].valueFrom.secretKeyRef` 에 채워야 한다. +1. 프로그램이 지정된 환경 변수에서 값을 찾도록 + 이미지 및/또는 커맨드 라인을 수정한다. + +다음은 환경 변수를 통해 시크릿을 사용하는 파드의 예시이다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: secret-env-pod +spec: + containers: + - name: mycontainer + image: redis + env: + - name: SECRET_USERNAME + valueFrom: + secretKeyRef: + name: mysecret + key: username + optional: false # 기본값과 동일하다 + # "mysecret"이 존재하고 "username"라는 키를 포함해야 한다 + - name: SECRET_PASSWORD + valueFrom: + secretKeyRef: + name: mysecret + key: password + optional: false # 기본값과 동일하다 + # "mysecret"이 존재하고 "password"라는 키를 포함해야 한다 + restartPolicy: Never +``` + + +#### 올바르지 않은 환경 변수 {#restriction-env-from-invalid} + +유효하지 않은 환경 변수 이름으로 간주되는 키가 있는 `envFrom` 필드로 +환경 변수를 채우는 데 사용되는 시크릿은 해당 키를 건너뛴다. +하지만 파드를 시작할 수는 있다. + +유효하지 않은 변수 이름이 파드 정의에 포함되어 있으면, +`reason`이 `InvalidVariableNames`로 설정된 이벤트와 +유효하지 않은 스킵된 키 목록 메시지가 파드 시작 실패 정보에 추가된다. +다음 예시는 2개의 유효하지 않은 키 `1badkey` 및 `2alsobad`를 포함하는 `mysecret` 시크릿을 참조하는 파드를 보여준다. + +```shell +kubectl get events +``` + +출력은 다음과 같다. + +``` +LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON +0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names. +``` + + +#### 환경 변수로부터 시크릿 값 사용하기 + +환경 변수 형태로 시크릿을 사용하는 컨테이너 내부에서, +시크릿 키는 일반적인 환경 변수로 보인다. +이러한 환경 변수의 값은 시크릿 데이터를 base64 디코드한 값이다. + +다음은 위 예시 컨테이너 내부에서 실행된 명령의 결과이다. + +```shell +echo "$SECRET_USERNAME" +``` + +출력 결과는 다음과 비슷하다. + +``` +admin +``` + +```shell +echo "$SECRET_PASSWORD" +``` + +출력 결과는 다음과 비슷하다. + +``` +1f2d1e2e67df +``` + +{{< note >}} +컨테이너가 이미 환경 변수 형태로 시크릿을 사용하는 경우, +컨테이너가 다시 시작되기 전에는 +시크릿 업데이트를 볼 수 없다. +시크릿이 변경되면 컨테이너 재시작을 트리거하는 써드파티 솔루션이 존재한다. +{{< /note >}} + +### 컨테이너 이미지 풀 시크릿 {#using-imagepullsecrets} + +비공개 저장소에서 컨테이너 이미지를 가져오고 싶다면, +각 노드의 kubelet이 해당 저장소에 인증을 수행하는 방법을 마련해야 한다. +이를 위해 _이미지 풀 시크릿_ 을 구성할 수 있다. +이러한 시크릿은 파드 수준에 설정된다. + +파드의 `imagePullSecrets` 필드는 파드가 속한 네임스페이스에 있는 시크릿들에 대한 참조 목록이다. +`imagePullSecrets`를 사용하여 이미지 저장소 접근 크리덴셜을 kubelet에 전달할 수 있다. +kubelet은 이 정보를 사용하여 파드 대신 비공개 이미지를 가져온다. +`imagePullSecrets` 필드에 대한 더 많은 정보는 +[파드 API 레퍼런스](/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec)의 +`PodSpec` 부분을 확인한다. + +#### imagePullSecrets 사용하기 + +`imagePullSecrets` 필드는 동일한 네임스페이스의 시크릿에 대한 참조 목록이다. +`imagePullSecrets` 를 사용하여 도커(또는 다른 컨테이너) 이미지 레지스트리 비밀번호가 포함된 시크릿을 kubelet에 전달할 수 있다. +kubelet은 이 정보를 사용해서 파드를 대신하여 프라이빗 이미지를 가져온다. +`imagePullSecrets` 필드에 대한 자세한 정보는 [PodSpec API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core)를 참고한다. + +##### imagePullSecret 수동으로 지정하기 + +[컨테이너 이미지](/ko/docs/concepts/containers/images/#파드에-imagepullsecrets-명시) 문서에서 +`imagePullSecrets`를 지정하는 방법을 배울 수 있다. + +##### imagePullSecrets가 자동으로 연결되도록 준비하기 + +수동으로 `imagePullSecrets` 를 생성하고, +서비스어카운트(ServiceAccount)에서 이들을 참조할 수 있다. +해당 서비스어카운트로 생성되거나 기본적인 서비스어카운트로 생성된 모든 파드는 +파드의 `imagePullSecrets` 필드를 가져오고 서비스 어카운트의 필드로 설정한다. +해당 프로세스에 대한 자세한 설명은 +[서비스 어카운트에 ImagePullSecrets 추가하기](/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account)를 참고한다. + +### 스태틱 파드에서의 시크릿 사용 {#restriction-static-pod} + +{{< glossary_tooltip text="스태틱(static) 파드" term_id="static-pod" >}}에서는 +컨피그맵이나 시크릿을 사용할 수 없다. + +## 사용 사레 + +### 사용 사례: 컨테이너 환경 변수로 사용하기 + +시크릿 정의를 작성한다. +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: mysecret +type: Opaque +data: + USER_NAME: YWRtaW4= + PASSWORD: MWYyZDFlMmU2N2Rm +``` + +시크릿을 생성한다. +```shell +kubectl apply -f mysecret.yaml +``` + +모든 시크릿 데이터를 컨테이너 환경 변수로 정의하는 데 `envFrom` 을 사용한다. 시크릿의 키는 파드의 환경 변수 이름이 된다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: secret-test-pod +spec: + containers: + - name: test-container + image: k8s.gcr.io/busybox + command: [ "/bin/sh", "-c", "env" ] + envFrom: + - secretRef: + name: mysecret + restartPolicy: Never +``` + +### 사용 사례: SSH 키를 사용하는 파드 + +몇 가지 SSH 키를 포함하는 시크릿을 생성한다. + +```shell +kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub +``` + +출력 결과는 다음과 비슷하다. + +``` +secret "ssh-key-secret" created +``` + +SSH 키를 포함하는 `secretGenerator` 필드가 있는 `kustomization.yaml` 를 만들 수도 있다. + +{{< caution >}} +사용자 자신의 SSH 키를 보내기 전에 신중하게 생각한다. +클러스터의 다른 사용자가 시크릿에 접근할 수 있게 될 수도 있기 때문이다. + +대신, 쿠버네티스 클러스터를 공유하는 모든 사용자가 접근할 수 있으면서도, +크리덴셜이 유출된 경우 폐기가 가능한 서비스 아이덴티티를 가리키는 +SSH 프라이빗 키를 만들 수 있다. +{{< /caution >}} + +이제 SSH 키를 가진 시크릿을 참조하고 +볼륨에서 시크릿을 사용하는 파드를 만들 수 있다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: secret-test-pod + labels: + name: secret-test +spec: + volumes: + - name: secret-volume + secret: + secretName: ssh-key-secret + containers: + - name: ssh-test-container + image: mySshImage + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" +``` + +컨테이너의 명령이 실행될 때, 다음 위치에서 키 부분을 사용할 수 있다. + +``` +/etc/secret-volume/ssh-publickey +/etc/secret-volume/ssh-privatekey +``` + +그러면 컨테이너는 SSH 연결을 맺기 위해 시크릿 데이터를 자유롭게 사용할 수 있다. + +### 사용 사례: 운영 / 테스트 자격 증명을 사용하는 파드 + +이 예제에서는 +운영 환경의 자격 증명이 포함된 시크릿을 사용하는 파드와 +테스트 환경의 자격 증명이 있는 시크릿을 사용하는 다른 파드를 보여준다. + +사용자는 `secretGenerator` 필드가 있는 `kustomization.yaml` 을 만들거나 +`kubectl create secret` 을 실행할 수 있다. + +```shell +kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11 +``` + +출력 결과는 다음과 비슷하다. + +``` +secret "prod-db-secret" created +``` + +테스트 환경의 자격 증명에 대한 시크릿을 만들 수도 있다. + +```shell +kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests +``` + +출력 결과는 다음과 비슷하다. + +``` +secret "test-db-secret" created +``` + +{{< note >}} +`$`, `\`, `*`, `=` 그리고 `!` 와 같은 특수 문자는 사용자의 [셸](https://ko.wikipedia.org/wiki/셸)에 의해 해석되고 이스케이핑이 필요하다. + +대부분의 셸에서 비밀번호를 이스케이프하는 가장 쉬운 방법은 작은 따옴표(`'`)로 묶는 것이다. +예를 들어, 실제 비밀번호가 `S!B\*d$zDsb=` 이면, 다음과 같은 명령을 실행해야 한다. + +```shell +kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb=' +``` + +파일(`--from-file`)에서는 비밀번호의 특수 문자를 이스케이프할 필요가 없다. +{{< /note >}} + +이제 파드를 생성한다. + +```shell +cat < pod.yaml +apiVersion: v1 +kind: List +items: +- kind: Pod + apiVersion: v1 + metadata: + name: prod-db-client-pod + labels: + name: prod-db-client + spec: + volumes: + - name: secret-volume + secret: + secretName: prod-db-secret + containers: + - name: db-client-container + image: myClientImage + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" +- kind: Pod + apiVersion: v1 + metadata: + name: test-db-client-pod + labels: + name: test-db-client + spec: + volumes: + - name: secret-volume + secret: + secretName: test-db-secret + containers: + - name: db-client-container + image: myClientImage + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" +EOF +``` + +동일한 `kustomization.yaml`에 파드를 추가한다. + +```shell +cat <> kustomization.yaml +resources: +- pod.yaml +EOF +``` + +다음을 실행하여 API 서버에 이러한 모든 오브젝트를 적용한다. + +```shell +kubectl apply -k . +``` + +두 컨테이너 모두 각 컨테이너의 환경에 대한 값을 가진 파일시스템에 +다음의 파일이 존재한다. + +``` +/etc/secret-volume/username +/etc/secret-volume/password +``` + +두 파드의 사양이 한 필드에서만 어떻게 다른지 확인한다. 이를 통해 +공통 파드 템플릿에서 다양한 기능을 가진 파드를 생성할 수 있다. + +두 개의 서비스 어카운트를 사용하여 기본 파드 명세를 더욱 단순화할 수 있다. + +1. `prod-db-secret` 을 가진 `prod-user` +1. `test-db-secret` 을 가진 `test-user` + +파드 명세는 다음과 같이 단축된다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: prod-db-client-pod + labels: + name: prod-db-client +spec: + serviceAccount: prod-db-client + containers: + - name: db-client-container + image: myClientImage +``` + +### 사용 사례: 시크릿 볼륨의 도트 파일(dotfile) + +점으로 시작하는 키를 정의하여 데이터를 "숨김"으로 만들 수 있다. +이 키는 도트 파일 또는 "숨겨진" 파일을 나타낸다. +예를 들어, 다음 시크릿이 `secret-volume` 볼륨에 마운트되면 아래와 같다. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: dotfile-secret +data: + .secret-file: dmFsdWUtMg0KDQo= +--- +apiVersion: v1 +kind: Pod +metadata: + name: secret-dotfiles-pod +spec: + volumes: + - name: secret-volume + secret: + secretName: dotfile-secret + containers: + - name: dotfile-test-container + image: k8s.gcr.io/busybox + command: + - ls + - "-l" + - "/etc/secret-volume" + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" +``` + +볼륨은 `.secret-file` 이라는 하나의 파일을 포함하고, +`dotfile-test-container` 는 `/etc/secret-volume/.secret-file` 경로에 +이 파일을 가지게 된다. + +{{< note >}} +`ls -l` 명령의 결과에서 숨겨진 점으로 시작하는 파일들은 +디렉터리 내용을 나열할 때 `ls -la` 를 사용해야 이 파일들을 볼 수 있다. +{{< /note >}} + +### 사용 사례: 파드의 한 컨테이너에 표시되는 시크릿 + +HTTP 요청을 처리하고, 복잡한 비즈니스 로직을 수행한 다음, HMAC이 있는 일부 메시지에 +서명해야 하는 프로그램을 고려한다. 애플리케이션 로직이 +복잡하기 때문에, 서버에서 눈에 띄지 않는 원격 파일 읽기 공격이 +있을 수 있으며, 이로 인해 개인 키가 공격자에게 노출될 수 있다. + +이는 두 개의 컨테이너의 두 개 프로세스로 나눌 수 있다. 사용자 상호 작용과 +비즈니스 로직을 처리하지만, 개인 키를 볼 수 없는 프론트엔드 컨테이너와 +개인 키를 볼 수 있고, 프론트엔드의 간단한 서명 요청(예를 들어, localhost 네트워킹을 통해)에 +응답하는 서명자 컨테이너로 나눌 수 있다. + +이 분할된 접근 방식을 사용하면, 공격자는 이제 애플리케이션 서버를 속여서 +파일을 읽는 것보다 다소 어려운 임의적인 어떤 작업을 수행해야 +한다. + ## 시크릿 타입 {#secret-types} 시크릿을 생성할 때, [`Secret`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#secret-v1-core) @@ -94,15 +850,20 @@ weight: 30 | `kubernetes.io/tls` | TLS 클라이언트나 서버를 위한 데이터 | | `bootstrap.kubernetes.io/token` | 부트스트랩 토큰 데이터 | -사용자는 시크릿 오브젝트의 `type` 값에 비어 있지 않은 문자열을 할당하여 자신만의 시크릿 -타입을 정의하고 사용할 수 있다. 비어 있는 문자열은 `Opaque` 타입으로 인식된다. -쿠버네티스는 타입 명칭에 제약을 부과하지는 않는다. 그러나 만약 -빌트인 타입 중 하나를 사용한다면, 해당 타입에 정의된 모든 요구 사항을 -만족시켜야 한다. +사용자는 시크릿 오브젝트의 `type` 값에 비어 있지 않은 문자열을 할당하여 자신만의 시크릿 타입을 정의하고 사용할 수 있다 +(비어 있는 문자열은 `Opaque` 타입으로 인식된다). + +쿠버네티스는 타입 명칭에 제약을 부과하지는 않는다. +그러나 만약 빌트인 타입 중 하나를 사용한다면, +해당 타입에 정의된 모든 요구 사항을 만족시켜야 한다. + +공개 사용을 위한 시크릿 타입을 정의하는 경우, 규칙에 따라 +`cloud-hosting.example.net/cloud-api-credentials`와 같이 시크릿 타입 이름 앞에 도메인 이름 및 `/`를 추가하여 +전체 시크릿 타입 이름을 구성한다. ### 불투명(Opaque) 시크릿 -`Opaque` 은 시크릿 구성 파일에서 누락된 경우의 기본 시크릿 타입이다. +`Opaque` 은 시크릿 구성 파일에서 시크릿 타입을 지정하지 않았을 경우의 기본 시크릿 타입이다. `kubectl` 을 사용하여 시크릿을 생성할 때 `Opaque` 시크릿 타입을 나타내기 위해서는 `generic` 하위 커맨드를 사용할 것이다. 예를 들어, 다음 커맨드는 타입 `Opaque` 의 비어 있는 시크릿을 생성한다. @@ -120,16 +881,20 @@ empty-secret Opaque 0 2m6s ``` 해당 `DATA` 열은 시크릿에 저장된 데이터 아이템의 수를 보여준다. -이 경우, `0` 은 비어 있는 시크릿을 하나 생성하였다는 것을 의미한다. +이 경우, `0` 은 비어 있는 시크릿을 생성하였다는 것을 의미한다. ### 서비스 어카운트 토큰 시크릿 -`kubernetes.io/service-account-token` 시크릿 타입은 서비스 어카운트를 확인하는 토큰을 저장하기 위해서 사용한다. 이 시크릿 타입을 사용할 때는, -`kubernetes.io/service-account.name` 어노테이션이 존재하는 서비스 -어카운트 이름으로 설정되도록 해야 한다. 쿠버네티스 컨트롤러는 -`kubernetes.io/service-account.uid` 및 실제 토큰 -콘텐츠로 설정된 `data` 필드의 `token` 키와 같은, -몇 가지 다른 필드들을 채운다. +`kubernetes.io/service-account-token` 시크릿 타입은 +{{< glossary_tooltip text="서비스 어카운트" term_id="service-account" >}}를 확인하는 +토큰을 저장하기 위해서 사용한다. +이 시크릿 타입을 사용할 때는, +`kubernetes.io/service-account.name` 어노테이션이 존재하는 +서비스 어카운트 이름으로 설정되도록 해야 한다. +쿠버네티스 {{< glossary_tooltip text="컨트롤러" term_id="controller" >}}는 +`kubernetes.io/service-account.uid` 어노테이션 및 +`data` 필드의 `token` 키와 같은 몇 가지 다른 필드들을 채우며, +이들은 인증 토큰을 보관한다. 다음은 서비스 어카운트 토큰 시크릿의 구성 예시이다. @@ -169,7 +934,7 @@ data: - `kubernetes.io/dockercfg` - `kubernetes.io/dockerconfigjson` -`kubernetes.io/dockercfg` 는 직렬화 된 도커 커맨드라인 구성을 +`kubernetes.io/dockercfg` 는 직렬화된 도커 커맨드라인 구성을 위한 기존(legacy) 포맷 `~/.dockercfg` 를 저장하기 위해 할당된 타입이다. 시크릿 타입을 사용할 때는, `data` 필드가 base64 포맷으로 인코딩된 `~/.dockercfg` 파일의 콘텐츠를 값으로 가지는 `.dockercfg` 키를 포함하고 있는지 @@ -196,8 +961,8 @@ data: ``` {{< note >}} -만약 base64 인코딩 수행을 원하지 않는다면, 그 대신 `stringData` 필드의 -사용을 선택할 수 있다. +만약 base64 인코딩 수행을 원하지 않는다면, +그 대신 `stringData` 필드를 사용할 수 있다. {{< /note >}} 이러한 타입들을 매니페스트를 사용하여 생성하는 경우, API @@ -210,37 +975,42 @@ data: ```shell kubectl create secret docker-registry secret-tiger-docker \ + --docker-email=tiger@acme.example \ --docker-username=tiger \ - --docker-password=pass113 \ - --docker-email=tiger@acme.com \ + --docker-password=pass1234 \ --docker-server=my-registry.example:5000 ``` -이 커맨드는 `kubernetes.io/dockerconfigjson` 타입의 시크릿을 생성한다. -만약 `data` 필드로부터 `.dockerconfigjson` 콘텐츠를 복사(dump)해오면, -다음과 같이 유효한 도커 JSON 콘텐츠를 -즉석에서 얻게 될 것이다. +이 커맨드는 `kubernetes.io/dockerconfigjson` 타입의 시크릿을 생성한다. +다음 명령으로 이 새 시크릿에서 `.data.dockercfgjson` 필드를 덤프하고 +base64로 디코드하면, + +```shell +kubectl get secret secret-tiger-docker -o jsonpath='{.data.*}' | base64 -d +``` + +출력은 다음과 같은 JSON 문서이다(그리고 +이는 또한 유효한 도커 구성 파일이다). ```json { - "apiVersion": "v1", - "data": { - ".dockerconfigjson": "eyJhdXRocyI6eyJteS1yZWdpc3RyeTo1MDAwIjp7InVzZXJuYW1lIjoidGlnZXIiLCJwYXNzd29yZCI6InBhc3MxMTMiLCJlbWFpbCI6InRpZ2VyQGFjbWUuY29tIiwiYXV0aCI6ImRHbG5aWEk2Y0dGemN6RXhNdz09In19fQ==" - }, - "kind": "Secret", - "metadata": { - "creationTimestamp": "2021-07-01T07:30:59Z", - "name": "secret-tiger-docker", - "namespace": "default", - "resourceVersion": "566718", - "uid": "e15c1d7b-9071-4100-8681-f3a7a2ce89ca" - }, - "type": "kubernetes.io/dockerconfigjson" + "auths": { + "my-registry.example:5000": { + "username": "tiger", + "password": "pass1234", + "email": "tiger@acme.example", + "auth": "dGlnZXI6cGFzczEyMzQ=" + } + } } - ``` -### 기본 인증 시크릿 +{{< note >}} +위의 `auth` 값은 base64 인코딩되어 있다. 이는 난독화된 것이지 암호화된 것이 아니다. +이 시크릿을 읽을 수 있는 사람은 레지스트리 접근 베어러 토큰을 알 수 있는 것이다. +{{< /note >}} + +### 기본 인증(Basic authentication) 시크릿 `kubernetes.io/basic-auth` 타입은 기본 인증을 위한 자격 증명을 저장하기 위해 제공된다. 이 시크릿 타입을 사용할 때는 시크릿의 `data` 필드가 @@ -262,15 +1032,17 @@ metadata: name: secret-basic-auth type: kubernetes.io/basic-auth stringData: - username: admin - password: t0p-Secret + username: admin # kubernetes.io/basic-auth 에서 요구하는 필드 + password: t0p-Secret # kubernetes.io/basic-auth 에서 요구하는 필드 ``` -이 기본 인증 시크릿 타입은 사용자 편의만을 위해서 제공된다. -사용자는 기본 인증에서 사용되는 자격 증명을 위한 `Opaque` 를 생성할 수도 있다. -그러나, 빌트인 시크릿 타입을 사용하는 것은 사용자의 자격 증명들의 포맷을 통합하는 데 도움이 되고, -API 서버는 요구되는 키가 시크릿 구성에서 제공되고 있는지 -검증도 한다. +이 기본 인증 시크릿 타입은 오직 사용자 편의를 위해 제공되는 것이다. +사용자는 기본 인증에서 사용할 자격 증명을 위해 `Opaque` 타입의 시크릿을 생성할 수도 있다. +그러나, 미리 정의되어 공개된 시크릿 타입(`kubernetes.io/basic-auth`)을 사용하면 +다른 사람이 이 시크릿의 목적을 이해하는 데 도움이 되며, +예상되는 키 이름에 대한 규칙이 설정된다. +쿠버네티스 API는 이 유형의 시크릿에 대해 +필수 키가 설정되었는지 확인한다. ### SSH 인증 시크릿 @@ -279,7 +1051,8 @@ API 서버는 요구되는 키가 시크릿 구성에서 제공되고 있는지 키-값 쌍을 사용할 SSH 자격 증명으로 `data` (또는 `stringData`) 필드에 명시해야 할 것이다. -다음 YAML은 SSH 인증 시크릿의 구성 예시이다. +다음 매니페스트는 +SSH 공개/개인 키 인증에 사용되는 시크릿 예시이다. ```yaml apiVersion: v1 @@ -293,11 +1066,13 @@ data: MIIEpQIBAAKCAQEAulqb/Y ... ``` -SSH 인증 시크릿 타입은 사용자 편의만을 위해서 제공된다. -사용자는 SSH 인증에서 사용되는 자격 증명을 위한 `Opaque` 를 생성할 수도 있다. -그러나, 빌트인 시크릿 타입을 사용하는 것은 사용자의 자격 증명들의 포맷을 통합하는 데 도움이 되고, -API 서버는 요구되는 키가 시크릿 구성에서 제공되고 있는지 -검증도 한다. +SSH 인증 시크릿 타입은 오직 사용자 편의를 위해 제공되는 것이다. +사용자는 SSH 인증에서 사용할 자격 증명을 위해 `Opaque` 타입의 시크릿을 생성할 수도 있다. +그러나, 미리 정의되어 공개된 시크릿 타입(`kubernetes.io/ssh-auth`)을 사용하면 +다른 사람이 이 시크릿의 목적을 이해하는 데 도움이 되며, +예상되는 키 이름에 대한 규칙이 설정된다. +그리고 API 서버가 +시크릿 정의에 필수 키가 명시되었는지 확인한다. {{< caution >}} SSH 개인 키는 자체적으로 SSH 클라이언트와 호스트 서버 간에 신뢰할 수 있는 통신을 @@ -308,13 +1083,15 @@ SSH 개인 키는 자체적으로 SSH 클라이언트와 호스트 서버 간에 ### TLS 시크릿 -쿠버네티스는 보통 TLS를 위해 사용되는 인증서와 관련된 키를 저장하기 위해서 +쿠버네티스는 일반적으로 TLS를 위해 사용되는 인증서 및 관련된 키를 저장하기 위한 빌트인 시크릿 타입 `kubernetes.io/tls` 를 제공한다. -이 데이터는 인그레스 리소스의 TLS 종료에 주로 사용되지만, 다른 -리소스나 워크로드에 의해 직접적으로 사용될 수도 있다. -이 타입의 시크릿을 사용할 때는 `tls.key` 와 `tls.crt` 키가 시크릿 구성의 -`data` (또는 `stringData`) 필드에서 제공되어야 한다. 그러나, API -서버가 각 키에 대한 값이 유효한지 실제로 검증하지는 않는다. + +TLS 시크릿의 일반적인 용도 중 하나는 [인그레스](/ko/docs/concepts/services-networking/ingress/)에 대한 +전송 암호화(encryption in transit)를 구성하는 것이지만, +다른 리소스와 함께 사용하거나 워크로드에서 직접 사용할 수도 있다. +이 타입의 시크릿을 사용할 때는 `tls.key` 와 `tls.crt` 키가 +시크릿 구성의 `data` (또는 `stringData`) 필드에서 제공되어야 한다. +그러나, API 서버가 각 키에 대한 값이 유효한지 실제로 검증하지는 않는다. 다음 YAML은 TLS 시크릿을 위한 구성 예시를 포함한다. @@ -346,13 +1123,21 @@ kubectl create secret tls my-tls-secret \ --key=path/to/key/file ``` -공개/개인 키 쌍은 사전에 존재해야 한다. `--cert` 를 위한 공개 키 인증서는 -.PEM 으로 인코딩(Base64로 인코딩된 DER 포맷)되어야 하며, `--key` 를 위해 주어진 -개인 키에 맞아야 한다. -개인 키는 일반적으로 PEM 개인 키 포맷이라고 하는, -암호화되지 않은 형태(unencrypted)이어야 한다. 두 가지 방식 모두에 대해서, PEM의 -시작과 끝 라인(예를 들면, 인증서의 `--------BEGIN CERTIFICATE-----` 및 `-------END CERTIFICATE----`) -은 포함되면 *안* 된다. +공개/개인 키 쌍은 사전에 준비되어야 한다. +`--cert` 에 들어가는 공개 키 인증서는 +[RFC 7468의 섹션 5.1](https://datatracker.ietf.org/doc/html/rfc7468#section-5.1)에 있는 DER 형식이어야 하고, +`--key` 에 들어가는 개인 키 인증서는 +[RFC 7468의 섹션 11](https://datatracker.ietf.org/doc/html/rfc7468#section-11)에 있는 DER 형식 PKCS #8 을 따라야 한다. + +{{< note >}} +`kubernetes.io/tls` 시크릿은 +키 및 인증서에 Base64 인코드된 DER 데이터를 보관한다. +개인 키 및 인증서에 사용되는 PEM 형식에 익숙하다면, +이 base64 데이터는 PEM 형식에서 맨 윗줄과 아랫줄을 제거한 것과 동일하다. + +예를 들어, 인증서의 경우, +`--------BEGIN CERTIFICATE-----` 및 `-------END CERTIFICATE----` 줄은 포함되면 **안** 된다. +{{< /note >}} ### 부트스트랩 토큰 시크릿 @@ -421,367 +1206,23 @@ stringData: usage-bootstrap-signing: "true" ``` -## 시크릿 생성하기 -시크릿을 생성하기 위한 몇 가지 옵션이 있다. - -- [`kubectl` 명령을 사용하여 시크릿 생성하기](/ko/docs/tasks/configmap-secret/managing-secret-using-kubectl/) -- [구성 파일로 시크릿 생성하기](/ko/docs/tasks/configmap-secret/managing-secret-using-config-file/) -- [kustomize를 사용하여 시크릿 생성하기](/ko/docs/tasks/configmap-secret/managing-secret-using-kustomize/) - -## 시크릿 편집하기 - -기존 시크릿은 다음 명령을 사용하여 편집할 수 있다. - -```shell -kubectl edit secrets mysecret -``` - -이렇게 하면 기본으로 설정된 에디터가 열리고 `data` 필드에 base64로 인코딩된 시크릿 값을 업데이트할 수 있다. - -```yaml -# 아래 오브젝트를 수정한다. '#'로 시작하는 줄은 무시되고, -# 빈 파일은 편집이 취소될 것이다. 이 파일을 저장하는 도중에 오류가 발생하면 -# 관련 오류와 함께 다시 열린다. -# -apiVersion: v1 -data: - username: YWRtaW4= - password: MWYyZDFlMmU2N2Rm -kind: Secret -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: { ... } - creationTimestamp: 2016-01-22T18:41:56Z - name: mysecret - namespace: default - resourceVersion: "164619" - uid: cfee02d6-c137-11e5-8d73-42010af00002 -type: Opaque -``` - -## 시크릿 사용하기 - -시크릿은 데이터 볼륨으로 마운트되거나 파드의 컨테이너에서 사용할 -{{< glossary_tooltip text="환경 변수" term_id="container-env-variables" >}}로 -노출될 수 있다. 또한, 시크릿은 파드에 직접 노출되지 않고, -시스템의 다른 부분에서도 사용할 수 있다. 예를 들어, 시크릿은 -시스템의 다른 부분이 사용자를 대신해서 외부 시스템과 상호 작용하는 데 사용해야 하는 -자격 증명을 보유할 수 있다. - -### 시크릿을 파드의 파일로 사용하기 - -파드의 볼륨에서 시크릿을 사용하려면 다음과 같이 한다. - -1. 시크릿을 생성하거나 기존 시크릿을 사용한다. 여러 파드가 동일한 시크릿을 참조할 수 있다. -1. `.spec.volumes[].` 아래에 볼륨을 추가하려면 파드 정의를 수정한다. 볼륨의 이름을 뭐든지 지정하고, 시크릿 오브젝트의 이름과 동일한 `.spec.volumes[].secret.secretName` 필드를 생성한다. -1. 시크릿이 필요한 각 컨테이너에 `.spec.containers[].volumeMounts[]` 를 추가한다. 시크릿을 표시하려는 사용되지 않은 디렉터리 이름에 `.spec.containers[].volumeMounts[].readOnly = true` 와 `.spec.containers[].volumeMounts[].mountPath` 를 지정한다. -1. 프로그램이 해당 디렉터리에서 파일을 찾도록 이미지 또는 커맨드 라인을 수정한다. 시크릿 `data` 맵의 각 키는 `mountPath` 아래의 파일명이 된다. - -다음은 볼륨에 시크릿을 마운트하는 파드의 예시이다. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: mypod -spec: - containers: - - name: mypod - image: redis - volumeMounts: - - name: foo - mountPath: "/etc/foo" - readOnly: true - volumes: - - name: foo - secret: - secretName: mysecret -``` - -사용하려는 각 시크릿은 `.spec.volumes` 에서 참조해야 한다. - -파드에 여러 컨테이너가 있는 경우, 모든 컨테이너는 -자체 `volumeMounts` 블록이 필요하지만, 시크릿에 대해서는 시크릿당 하나의 `.spec.volumes` 만 필요하다. - -많은 파일을 하나의 시크릿으로 패키징하거나, 여러 시크릿을 사용할 수 있으며, 어느 쪽이든 편리한 방법을 사용하면 된다. - -#### 특정 경로에 대한 시크릿 키 투영하기 - -시크릿 키가 투영되는 볼륨 내 경로를 제어할 수도 있다. -`.spec.volumes[].secret.items` 필드를 사용하여 각 키의 대상 경로를 변경할 수 있다. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: mypod -spec: - containers: - - name: mypod - image: redis - volumeMounts: - - name: foo - mountPath: "/etc/foo" - readOnly: true - volumes: - - name: foo - secret: - secretName: mysecret - items: - - key: username - path: my-group/my-username -``` - -다음과 같은 일들이 일어날 것이다. - -* `username` 시크릿은 `/etc/foo/username` 대신 `/etc/foo/my-group/my-username` 아래의 파일에 저장된다. -* `password` 시크릿은 투영되지 않는다. - -`.spec.volumes[].secret.items` 를 사용하면, `items` 에 지정된 키만 투영된다. -시크릿의 모든 키를 사용하려면, 모든 키가 `items` 필드에 나열되어야 한다. -나열된 모든 키는 해당 시크릿에 존재해야 한다. 그렇지 않으면, 볼륨이 생성되지 않는다. - -#### 시크릿 파일 퍼미션 - -단일 시크릿 키에 대한 파일 접근 퍼미션 비트를 설정할 수 있다. -만약 사용자가 퍼미션을 지정하지 않는다면, 기본적으로 `0644` 가 사용된다. -전체 시크릿 볼륨에 대한 기본 모드를 설정하고 필요한 경우 키별로 오버라이드할 수도 있다. - -예를 들어, 다음과 같은 기본 모드를 지정할 수 있다. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: mypod -spec: - containers: - - name: mypod - image: redis - volumeMounts: - - name: foo - mountPath: "/etc/foo" - volumes: - - name: foo - secret: - secretName: mysecret - defaultMode: 0400 -``` - -그러고 나면, 시크릿이 `/etc/foo` 에 마운트되고 시크릿 볼륨 마운트로 생성된 -모든 파일의 퍼미션은 `0400` 이 될 것이다. - -참고로 JSON 스펙은 8진수 표기법을 지원하지 않으므로, 0400 퍼미션에 대해서 -값 256을 사용한다. 파드에 대해 JSON 대신 YAML을 사용하는 경우, 8진수 표기법을 -사용하여 보다 자연스러운 방식으로 퍼미션을 지정할 수 있다. - -참고로 파드에 `kubectl exec` 을 사용하는 경우, 예상되는 파일 모드를 찾기 위해 -심볼릭 링크를 따라가야 한다. 예를 들면, 다음과 같다. - -파드에서 시크릿 파일 모드를 확인한다. -``` -kubectl exec mypod -it sh - -cd /etc/foo -ls -l -``` - -출력 결과는 다음과 비슷하다. -``` -total 0 -lrwxrwxrwx 1 root root 15 May 18 00:18 password -> ..data/password -lrwxrwxrwx 1 root root 15 May 18 00:18 username -> ..data/username -``` - -올바른 파일 모드를 찾으려면 심볼릭 링크를 따라간다. - -``` -cd /etc/foo/..data -ls -l -``` - -출력 결과는 다음과 비슷하다. -``` -total 8 --r-------- 1 root root 12 May 18 00:18 password --r-------- 1 root root 5 May 18 00:18 username -``` - -이전 예제에서와 같이 매핑을 사용하여, 다음과 같이 -다른 파일에 대해 다른 퍼미션을 지정할 수도 있다. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: mypod -spec: - containers: - - name: mypod - image: redis - volumeMounts: - - name: foo - mountPath: "/etc/foo" - volumes: - - name: foo - secret: - secretName: mysecret - items: - - key: username - path: my-group/my-username - mode: 0777 -``` - -이 경우, `/etc/foo/my-group/my-username` 에 있는 파일은 -결과적으로 `0777` 퍼미션 값을 갖게 된다. JSON을 사용하는 경우, JSON 제한으로 인해 -10진수 표기법(`511`)으로 모드를 지정해야 한다. - -참고로 이 퍼미션 값은 나중에 읽을 때 10진수 표기법으로 -표시될 수 있다. - -#### 볼륨에서 시크릿 값 사용하기 - -시크릿 볼륨을 마운트하는 컨테이너 내부에서, 시크릿 키는 파일로 -나타나고 시크릿 값은 base64로 디코딩되어 이런 파일 내에 저장된다. -다음은 위의 예에서 컨테이너 내부에서 실행된 명령의 결과이다. - -```shell -ls /etc/foo/ -``` - -출력 결과는 다음과 비슷하다. - -``` -username -password -``` - -```shell -cat /etc/foo/username -``` - -출력 결과는 다음과 비슷하다. - -``` -admin -``` - -```shell -cat /etc/foo/password -``` - -출력 결과는 다음과 비슷하다. - -``` -1f2d1e2e67df -``` - -컨테이너의 프로그램은 파일에서 시크릿을 읽는 역할을 -한다. - -#### 마운트된 시크릿은 자동으로 업데이트됨 - -볼륨에서 현재 사용되는 시크릿이 업데이트되면, 투영된 키도 결국 업데이트된다. -kubelet은 마운트된 시크릿이 모든 주기적인 동기화에서 최신 상태인지 여부를 확인한다. -그러나, kubelet은 시크릿의 현재 값을 가져 오기 위해 로컬 캐시를 사용한다. -캐시의 유형은 [KubeletConfiguration 구조체](/docs/reference/config-api/kubelet-config.v1beta1/)의 -`ConfigMapAndSecretChangeDetectionStrategy` 필드를 사용하여 구성할 수 있다. -시크릿은 watch(기본값), ttl 기반 또는 API 서버로 모든 요청을 직접 -리디렉션하여 전파할 수 있다. -결과적으로, 시크릿이 업데이트된 순간부터 새로운 키가 파드에 투영되는 -순간까지의 총 지연 시간은 kubelet 동기화 시간 + 캐시 -전파 지연만큼 길 수 있다. 여기서 캐시 전파 지연은 선택한 캐시 유형에 따라 -달라질 수 있다(캐시 전파 지연은 각 캐시 유형에 따라 watch 전파 지연, 캐시의 ttl, 또는 0 에 상응함). - -{{< note >}} -시크릿을 [subPath](/ko/docs/concepts/storage/volumes/#subpath-사용하기) -볼륨 마운트로 사용하는 컨테이너는 시크릿 업데이트를 -받지 않는다. -{{< /note >}} - -### 시크릿을 환경 변수로 사용하기 - -파드에서 {{< glossary_tooltip text="환경 변수" term_id="container-env-variables" >}}에 -시크릿을 사용하려면 다음과 같이 한다. - -1. 시크릿을 생성하거나 기존 시크릿을 사용한다. 여러 파드가 동일한 시크릿을 참조할 수 있다. -1. 사용하려는 각 시크릿 키에 대한 환경 변수를 추가하려면 시크릿 키 값을 사용하려는 각 컨테이너에서 파드 정의를 수정한다. 시크릿 키를 사용하는 환경 변수는 시크릿의 이름과 키를 `env[].valueFrom.secretKeyRef` 에 채워야 한다. -1. 프로그램이 지정된 환경 변수에서 값을 찾도록 이미지 및/또는 커맨드 라인을 수정한다. - -다음은 환경 변수의 시크릿을 사용하는 파드의 예시이다. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: secret-env-pod -spec: - containers: - - name: mycontainer - image: redis - env: - - name: SECRET_USERNAME - valueFrom: - secretKeyRef: - name: mysecret - key: username - - name: SECRET_PASSWORD - valueFrom: - secretKeyRef: - name: mysecret - key: password - restartPolicy: Never -``` - -#### 환경 변수에서 시크릿 값 사용하기 - -환경 변수에서 시크릿을 사용하는 컨테이너 내부에서, 시크릿 키는 -시크릿 데이터의 base64 디코딩된 값을 포함하는 일반 환경 변수로 나타난다. -다음은 위의 예에서 컨테이너 내부에서 실행된 명령의 결과이다. - -```shell -echo $SECRET_USERNAME -``` - -출력 결과는 다음과 비슷하다. - -``` -admin -``` - -```shell -echo $SECRET_PASSWORD -``` - -출력 결과는 다음과 비슷하다. - -``` -1f2d1e2e67df -``` - -#### 시크릿 업데이트 후 환경 변수가 업데이트되지 않음 - -컨테이너가 환경 변수에서 이미 시크릿을 사용하는 경우, 다시 시작하지 않는 한 컨테이너에서 시크릿 업데이트를 볼 수 없다. -시크릿이 변경될 때 재시작을 트리거하는 써드파티 솔루션이 있다. - -## 변경할 수 없는(immutable) 시크릿 {#secret-immutable} +## 수정 불가능한(immutable) 시크릿 {#secret-immutable} {{< feature-state for_k8s_version="v1.21" state="stable" >}} -쿠버네티스 기능인 _변경할 수 없는 시크릿과 컨피그맵_ 은 -개별 시크릿과 컨피그맵을 변경할 수 없는 것으로 설정하는 옵션을 제공한다. 시크릿을 광범위하게 사용하는 -클러스터(최소 수만 개의 고유한 시크릿이 파드에 마운트)의 경우, 데이터 변경을 방지하면 -다음과 같은 이점이 있다. +쿠버네티스에서 특정 시크릿(및 컨피그맵)을 _수정 불가능_ 으로 표시할 수 있다. +기존 시크릿 데이터의 변경을 금지시키면 다음과 같은 이점을 가진다. -- 애플리케이션 중단을 유발할 수 있는 우발적(또는 원하지 않는) 업데이트로부터 보호 -- immutable로 표시된 시크릿에 대한 감시를 중단하여, kube-apiserver의 부하를 -크게 줄임으로써 클러스터의 성능을 향상시킴 +- 잘못된(또는 원치 않은) 업데이트를 차단하여 애플리케이션 중단을 방지 +- (수만 개 이상의 시크릿-파드 마운트와 같이 시크릿을 대규모로 사용하는 클러스터의 경우,) + 수정 불가능한 시크릿으로 전환하면 kube-apiserver의 부하를 크게 줄여 클러스터의 성능을 향상시킬 수 있다. + kubelet은 수정 불가능으로 지정된 시크릿에 대해서는 + [감시(watch)]를 유지할 필요가 없기 때문이다. -이 기능은 v1.19부터 기본적으로 활성화된 `ImmutableEphemeralVolumes` -[기능 게이트](/ko/docs/reference/command-line-tools-reference/feature-gates/)에 -의해 제어된다. `immutable` 필드를 `true` 로 설정하여 -변경할 수 없는 시크릿을 생성할 수 있다. 다음은 예시이다. +### 시크릿을 수정 불가능으로 지정하기 {#secret-immutable-create} + +다음과 같이 시크릿의 `immutable` 필드를 `true`로 설정하여 수정 불가능한 시크릿을 만들 수 있다. ```yaml apiVersion: v1 kind: Secret @@ -792,395 +1233,19 @@ data: immutable: true ``` -{{< note >}} -시크릿 또는 컨피그맵을 immutable로 표시하면, 이 변경 사항을 되돌리거나 -`data` 필드 내용을 변경할 수 _없다_. 시크릿을 삭제하고 다시 생성할 수만 있다. -기존 파드는 삭제된 시크릿에 대한 마운트 포인트를 유지하며, 이러한 파드를 다시 생성하는 것을 -권장한다. -{{< /note >}} - -### imagePullSecrets 사용하기 - -`imagePullSecrets` 필드는 동일한 네임스페이스의 시크릿에 대한 참조 목록이다. -`imagePullSecretsDocker` 를 사용하여 도커(또는 다른 컨테이너) 이미지 레지스트리 -비밀번호가 포함된 시크릿을 kubelet에 전달할 수 있다. kubelet은 이 정보를 사용해서 파드를 대신하여 프라이빗 이미지를 가져온다. -`imagePullSecrets` 필드에 대한 자세한 정보는 [PodSpec API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core)를 참고한다. - -#### imagePullSecret 수동으로 지정하기 - -[컨테이너 이미지 문서](/ko/docs/concepts/containers/images/#파드에-imagepullsecrets-명시)에서 `ImagePullSecrets` 지정하는 방법을 배울 수 있다. - -### imagePullSecrets가 자동으로 연결되도록 정렬하기 - -수동으로 `imagePullSecrets` 를 생성하고, 서비스어카운트(ServiceAccount)에서 -참조할 수 있다. 해당 서비스어카운트로 생성되거나 -기본적인 서비스어카운트로 생성된 모든 파드는 파드의 `imagePullSecrets` -필드를 가져오고 서비스 어카운트의 필드로 설정한다. -해당 프로세스에 대한 자세한 설명은 -[서비스 어카운트에 ImagePullSecrets 추가하기](/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account)를 참고한다. - -## 상세 내용 - -### 제약 사항 - -시크릿 볼륨 소스는 지정된 오브젝트 참조가 -실제로 시크릿 유형의 오브젝트를 가리키는지 확인하기 위해 유효성을 검사한다. 따라서, 시크릿에 -의존하는 모든 파드보다 먼저 시크릿을 만들어야 한다. - -시크릿 리소스는 {{< glossary_tooltip text="네임스페이스" term_id="namespace" >}}에 존재한다. -시크릿은 동일한 네임스페이스에 있는 파드에서만 참조할 수 있다. - -개별 시크릿의 크기는 1MiB로 제한된다. 이는 API 서버와 -kubelet 메모리를 소진시키는 매우 큰 시크릿 생성을 막기 위한 것이다. -그러나, 많은 작은 시크릿을 만들어도 메모리가 고갈될 수 있다. 시크릿으로 -인한 메모리 사용에 대한 보다 포괄적인 제한은 향후 버전에 계획된 기능이다. - -kubelet은 API 서버에서 시크릿을 가져오는 파드에 대한 -시크릿 사용만 지원한다. -여기에는 `kubectl` 을 사용하거나, 레플리케이션 컨트롤러를 통해 간접적으로 생성된 모든 -파드가 포함된다. kubelet의 `--manifest-url` 플래그, `--config` 플래그 또는 -kubectl의 REST API(이 방법들은 파드를 생성하는 일반적인 방법이 아님)로 -생성된 파드는 포함하지 않는다. -{{< glossary_tooltip text="스태틱(static) 파드" term_id="static-pod" >}}의 `spec`은 컨피그맵 -또는 다른 API 오브젝트를 참조할 수 없다. - - -시크릿은 optional(선택 사항)로 표시되지 않는 한 파드에서 환경 -변수로 사용되기 전에 생성되어야 한다. 존재하지 않는 시크릿을 -참조하면 파드가 시작되지 않는다. - -명명된 시크릿에 존재하지 않는 키에 대한 참조(`secretKeyRef` 필드)는 -파드가 시작되지 않도록 한다. - -잘못된 환경 변수 이름으로 간주되는 키가 있는 `envFrom` 필드로 -환경 변수를 채우는 데 사용되는 시크릿은 해당 키를 -건너뛴다. 이러면 해당 파드가 시작될 수 있다. 원인이 `InvalidVariableNames` 인 -이벤트가 발생하며 건너뛴 유효하지 않은 키 목록이 -포함된 메시지가 생성된다. 다음의 예는 2개의 유효하지 않은 -키(`1badkey` 와 `2alsobad`)가 포함된 default/mysecret을 참조하는 파드를 보여준다. - -```shell -kubectl get events -``` - -출력 결과는 다음과 비슷하다. - -``` -LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON -0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names. -``` - -### 시크릿 및 파드 수명 상호 작용 - -쿠버네티스 API를 호출하여 파드가 생성될 때, 참조된 시크릿이 있는지 확인하지 -않는다. 일단 파드가 스케줄되면, kubelet은 시크릿 값 가져오기를 -시도한다. 시크릿이 존재하지 않거나 API 서버에 대한 -일시적인 연결 부족으로 인해 시크릿을 가져올 수 없는 경우, kubelet은 -주기적으로 재시도한다. kubelet은 아직 시작되지 않은 이유를 설명하는 -파드에 대한 이벤트를 보고한다. 시크릿을 가져오면, kubelet은 -이를 포함하는 볼륨을 생성하고 마운트한다. 모든 파드의 볼륨이 -마운트될 때까지 파드의 컨테이너는 시작되지 않는다. - -## 사용 사레 - -### 사용 사례: 컨테이너 환경 변수로 사용하기 - -시크릿 정의를 작성한다. - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: mysecret -type: Opaque -data: - USER_NAME: YWRtaW4= - PASSWORD: MWYyZDFlMmU2N2Rm -``` - -시크릿을 생성한다. - -```shell -kubectl apply -f mysecret.yaml -``` - -모든 시크릿 데이터를 컨테이너 환경 변수로 정의하는 데 `envFrom` 을 사용한다. 시크릿의 키는 파드의 환경 변수 이름이 된다. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: secret-test-pod -spec: - containers: - - name: test-container - image: k8s.gcr.io/busybox - command: [ "/bin/sh", "-c", "env" ] - envFrom: - - secretRef: - name: mysecret - restartPolicy: Never -``` - -### 사용 사례: ssh 키가 있는 파드 - -몇 가지 ssh 키를 포함하는 시크릿을 생성한다. - -```shell -kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub -``` - -출력 결과는 다음과 비슷하다. - -``` -secret "ssh-key-secret" created -``` - -ssh 키를 포함하는 `secretGenerator` 필드가 있는 `kustomization.yaml` 를 만들 수도 있다. - -{{< caution >}} -사용자 자신의 ssh 키를 보내기 전에 신중하게 생각한다. 클러스터의 다른 사용자가 시크릿에 접근할 수 있다. 쿠버네티스 클러스터를 공유하는 모든 사용자가 접근할 수 있도록 하려는 서비스 어카운트를 사용하고, 사용자가 손상된 경우 이 계정을 취소할 수 있다. -{{< /caution >}} - -이제 ssh 키를 가진 시크릿을 참조하고 -볼륨에서 시크릿을 사용하는 파드를 만들 수 있다. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: secret-test-pod - labels: - name: secret-test -spec: - volumes: - - name: secret-volume - secret: - secretName: ssh-key-secret - containers: - - name: ssh-test-container - image: mySshImage - volumeMounts: - - name: secret-volume - readOnly: true - mountPath: "/etc/secret-volume" -``` - -컨테이너의 명령이 실행될 때, 다음 위치에서 키 부분을 사용할 수 있다. - -``` -/etc/secret-volume/ssh-publickey -/etc/secret-volume/ssh-privatekey -``` - -그러면 컨테이너는 ssh 연결을 맺기 위해 시크릿 데이터를 자유롭게 사용할 수 있다. - -### 사용 사례: 운영 / 테스트 자격 증명이 있는 파드 - -이 예제에서는 운영 환경의 자격 증명이 포함된 시크릿을 -사용하는 파드와 테스트 환경의 자격 증명이 있는 시크릿을 사용하는 다른 파드를 -보여준다. - -사용자는 `secretGenerator` 필드가 있는 `kustomization.yaml` 을 만들거나 -`kubectl create secret` 을 실행할 수 있다. - -```shell -kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11 -``` - -출력 결과는 다음과 비슷하다. - -``` -secret "prod-db-secret" created -``` - -테스트 환경의 자격 증명에 대한 시크릿을 만들 수도 있다. - -```shell -kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests -``` - -출력 결과는 다음과 비슷하다. - -``` -secret "test-db-secret" created -``` +또한 기존의 수정 가능한 시크릿을 변경하여 수정 불가능한 시크릿으로 바꿀 수도 있다. {{< note >}} -`$`, `\`, `*`, `=` 그리고 `!` 와 같은 특수 문자는 사용자의 [셸](https://ko.wikipedia.org/wiki/셸)에 의해 해석되고 이스케이핑이 필요하다. -대부분의 셸에서 비밀번호를 이스케이프하는 가장 쉬운 방법은 작은 따옴표(`'`)로 묶는 것이다. -예를 들어, 실제 비밀번호가 `S!B\*d$zDsb=` 이면, 다음과 같은 명령을 실행해야 한다. - -```shell -kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb=' -``` - -파일(`--from-file`)에서는 비밀번호의 특수 문자를 이스케이프할 필요가 없다. +시크릿 또는 컨피그맵이 수정 불가능으로 지정되면, 이 변경을 취소하거나 `data` 필드의 내용을 바꿀 수 _없다_. +시크릿을 삭제하고 다시 만드는 것만 가능하다. +기존의 파드는 삭제된 시크릿으로의 마운트 포인트를 유지하기 때문에, +이러한 파드는 재생성하는 것을 추천한다. {{< /note >}} -이제 파드를 생성한다. +## 시크릿을 위한 정보 보안(Information security) -```shell -cat < pod.yaml -apiVersion: v1 -kind: List -items: -- kind: Pod - apiVersion: v1 - metadata: - name: prod-db-client-pod - labels: - name: prod-db-client - spec: - volumes: - - name: secret-volume - secret: - secretName: prod-db-secret - containers: - - name: db-client-container - image: myClientImage - volumeMounts: - - name: secret-volume - readOnly: true - mountPath: "/etc/secret-volume" -- kind: Pod - apiVersion: v1 - metadata: - name: test-db-client-pod - labels: - name: test-db-client - spec: - volumes: - - name: secret-volume - secret: - secretName: test-db-secret - containers: - - name: db-client-container - image: myClientImage - volumeMounts: - - name: secret-volume - readOnly: true - mountPath: "/etc/secret-volume" -EOF -``` - -동일한 kustomization.yaml에 파드를 추가한다. - -```shell -cat <> kustomization.yaml -resources: -- pod.yaml -EOF -``` - -다음을 실행하여 API 서버에 이러한 모든 오브젝트를 적용한다. - -```shell -kubectl apply -k . -``` - -두 컨테이너 모두 각 컨테이너의 환경에 대한 값을 가진 파일시스템에 다음의 파일이 존재한다. - -``` -/etc/secret-volume/username -/etc/secret-volume/password -``` - -두 파드의 사양이 한 필드에서만 어떻게 다른지 확인한다. 이를 통해 -공통 파드 템플릿에서 다양한 기능을 가진 파드를 생성할 수 있다. - -두 개의 서비스 어카운트를 사용하여 기본 파드 명세를 더욱 단순화할 수 있다. - -1. `prod-db-secret` 을 가진 `prod-user` -1. `test-db-secret` 을 가진 `test-user` - -파드 명세는 다음과 같이 단축된다. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: prod-db-client-pod - labels: - name: prod-db-client -spec: - serviceAccount: prod-db-client - containers: - - name: db-client-container - image: myClientImage -``` - -### 사용 사례: 시크릿 볼륨의 도트 파일(dotfile) - -점으로 시작하는 키를 정의하여 데이터를 "숨김"으로 만들 수 있다. -이 키는 도트 파일 또는 "숨겨진" 파일을 나타낸다. 예를 들어, 다음 시크릿이 `secret-volume` 볼륨에 -마운트되면 아래와 같다. - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: dotfile-secret -data: - .secret-file: dmFsdWUtMg0KDQo= ---- -apiVersion: v1 -kind: Pod -metadata: - name: secret-dotfiles-pod -spec: - volumes: - - name: secret-volume - secret: - secretName: dotfile-secret - containers: - - name: dotfile-test-container - image: k8s.gcr.io/busybox - command: - - ls - - "-l" - - "/etc/secret-volume" - volumeMounts: - - name: secret-volume - readOnly: true - mountPath: "/etc/secret-volume" -``` - -볼륨은 `.secret-file` 이라는 하나의 파일을 포함하고, -`dotfile-test-container` 는 `/etc/secret-volume/.secret-file` 경로에 -이 파일을 가지게 된다. - -{{< note >}} -`ls -l` 명령의 결과에서 숨겨진 점으로 시작하는 파일들은 -디렉터리 내용을 나열할 때 `ls -la` 를 사용해야 이 파일들을 볼 수 있다. -{{< /note >}} - -### 사용 사례: 파드의 한 컨테이너에 표시되는 시크릿 - -HTTP 요청을 처리하고, 복잡한 비즈니스 로직을 수행한 다음, HMAC이 있는 일부 메시지에 -서명해야 하는 프로그램을 고려한다. 애플리케이션 로직이 -복잡하기 때문에, 서버에서 눈에 띄지 않는 원격 파일 읽기 공격이 -있을 수 있으며, 이로 인해 개인 키가 공격자에게 노출될 수 있다. - -이는 두 개의 컨테이너의 두 개 프로세스로 나눌 수 있다. 사용자 상호 작용과 -비즈니스 로직을 처리하지만, 개인 키를 볼 수 없는 프론트엔드 컨테이너와 -개인 키를 볼 수 있고, 프론트엔드의 간단한 서명 요청(예를 들어, localhost 네트워킹을 통해)에 -응답하는 서명자 컨테이너로 나눌 수 있다. - -이 분할된 접근 방식을 사용하면, 공격자는 이제 애플리케이션 서버를 속여서 -파일을 읽는 것보다 다소 어려운 임의적인 어떤 작업을 수행해야 -한다. - - - -## 모범 사례 - -### 시크릿 API를 사용하는 클라이언트 - -시크릿 API와 상호 작용하는 애플리케이션을 배포할 때, -[RBAC](/docs/reference/access-authn-authz/rbac/)과 같은 -[인가 정책](/ko/docs/reference/access-authn-authz/authorization/)을 -사용하여 접근을 제한해야 한다. +컨피그맵과 시크릿은 비슷하게 동작하지만, +쿠버네티스는 시크릿 오브젝트에 대해 약간의 추가적인 보호 조치를 적용한다. 시크릿은 종종 다양한 중요도에 걸친 값을 보유하며, 이 중 많은 부분이 쿠버네티스(예: 서비스 어카운트 토큰)와 외부 시스템으로 단계적으로 @@ -1188,78 +1253,78 @@ HTTP 요청을 처리하고, 복잡한 비즈니스 로직을 수행한 다음, 동일한 네임스페이스 내의 다른 앱이 이러한 가정을 무효화할 수 있다. -이러한 이유로 네임스페이스 내 시크릿에 대한 `watch` 와 `list` 요청은 -매우 강력한 기능이며, 시크릿을 나열하면 클라이언트가 해당 네임스페이스에 -있는 모든 시크릿의 값을 검사할 수 있기 때문에 피해야 한다. 클러스터의 -모든 시크릿을 감시(`watch`)하고 나열(`list`)하는 기능은 가장 특권이 있는 시스템 레벨의 -컴포넌트에 대해서만 예약되어야 한다. +해당 노드의 파드가 필요로 하는 경우에만 시크릿이 노드로 전송된다. +시크릿을 파드 내부로 마운트할 때, 기밀 데이터가 보존적인(durable) 저장소에 기록되지 않도록 하기 위해 +kubelet이 데이터 복제본을 `tmpfs`에 저장한다. +해당 시크릿을 사용하는 파드가 삭제되면, +kubelet은 시크릿에 있던 기밀 데이터의 로컬 복사본을 삭제한다. -시크릿 API에 접근해야 하는 애플리케이션은 필요한 시크릿에 대한 `get` 요청을 -수행해야 한다. 이를 통해 관리자는 앱에 필요한 -[개별 인스턴스에 대한 접근을 허용 목록에 추가](/docs/reference/access-authn-authz/rbac/#referring-to-resources)하면서 모든 시크릿에 대한 접근을 -제한할 수 있다. +파드에는 여러 개의 컨테이너가 있을 수 있다. +기본적으로, 사용자가 정의한 컨테이너는 기본 서비스어카운트 및 이에 연관된 시크릿에만 접근할 수 있다. +다른 시크릿에 접근할 수 있도록 하려면 +명시적으로 환경 변수를 정의하거나 컨테이너 내에 볼륨을 맵핑해야 한다. -`get` 반복을 통한 성능 향상을 위해, 클라이언트는 시크릿을 -참조한 다음 리소스를 감시(`watch`)하고, 참조가 변경되면 시크릿을 다시 요청하는 리소스를 -설계할 수 있다. 덧붙여, 클라이언트에게 개별 리소스를 감시(`watch`)하도록 하는 ["대량 감시" API](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/bulk_watch.md)도 -제안되었으며, 쿠버네티스의 후속 릴리스에서 사용할 수 -있을 것이다. - -## 보안 속성 - -### 보호 - -시크릿은 시크릿을 사용하는 파드와 독립적으로 생성될 수 -있으므로, 파드 생성, 보기, 편집 워크플로 중에 -시크릿이 노출될 위험이 적다. 또한 시스템은 가능한 경우 -디스크에 기록하지 않는 등 시크릿에 대한 추가 예방 조치를 -취할 수 있다. - -해당 노드의 파드에 필요한 경우에만 시크릿이 노드로 전송된다. -kubelet은 시크릿이 디스크 저장소에 기록되지 않도록 시크릿을 -`tmpfs` 에 저장한다. 일단 시크릿에 의존하는 파드가 삭제되면, kubelet은 -시크릿 데이터의 로컬 복제본도 삭제한다. - -동일한 노드의 여러 파드에 대한 시크릿이 있을 수 있다. 그러나 -파드가 요청하는 시크릿만 해당 컨테이너 내에서 잠재적으로 볼 수 있다. +동일한 노드의 여러 파드에 대한 시크릿이 있을 수 있다. +그러나 잠재적으로는 파드가 요청한 시크릿만 해당 파드의 컨테이너 내에서 볼 수 있다. 따라서, 하나의 파드는 다른 파드의 시크릿에 접근할 수 없다. -파드에는 여러 개의 컨테이너가 있을 수 있다. 그러나, 파드의 각 컨테이너는 -컨테이너 내에서 볼 수 있도록 파드의 `volumeMounts` 에 있는 시크릿 볼륨을 -요청해야 한다. 이것은 유용한 [파드 레벨에서의 보안 -파티션](#사용-사례-파드의-한-컨테이너에-표시되는-시크릿)을 구성하는 데 사용할 수 있다. +{{< warning >}} +노드 상의 높은 권한을 갖는(privileged) 컨테이너는 +해당 노드에 있는 모든 시크릿에 접근할 수 있다. +{{< /warning >}} -대부분의 쿠버네티스 배포판에서, 사용자와 API 서버 간, -API 서버에서 kubelet으로의 통신은 SSL/TLS로 보호된다. -이러한 채널을 통해 전송될 때 시크릿이 보호된다. -{{< feature-state for_k8s_version="v1.13" state="beta" >}} +### 개발자를 위한 보안 추천 사항 -시크릿 데이터에 대해 [저장 시 암호화(encryption at rest)](/docs/tasks/administer-cluster/encrypt-data/)를 -활성화할 수 있으며, 이를 통해 보안성에 대한 보장 없이는 시크릿이 {{< glossary_tooltip term_id="etcd" >}}에 저장되지 않도록 한다 . +- 애플리케이션은 환경 변수 또는 볼륨에서 기밀 정보를 읽은 뒤에 기밀 정보를 계속 보호해야 한다. + 예를 들어, 애플리케이션은 비밀 데이터를 암호화되지 않은 상태로 기록하거나 + 신뢰할 수 없는 당사자에게 전송하지 말아야 한다. +- 파드에 여러 컨테이너가 있고, + 그 중 한 컨테이너만 시크릿에 접근해야 하는 경우, + 다른 컨테이너는 해당 시크릿에 접근할 수 없도록 + 볼륨 마운트 또는 환경 변수 구성을 적절히 정의한다. +- {{< glossary_tooltip text="매니페스트" term_id="manifest" >}}를 통해 시크릿을 구성하고, + 이 안에 비밀 데이터가 base64로 인코딩된 경우, + 이 파일을 공유하거나 소스 저장소에 올리면 + 해당 매니페스트를 읽을 수 있는 모든 사람이 이 비밀 정보를 볼 수 있음에 주의한다. + base64 인코딩은 암호화 수단이 _아니기 때문에_, 평문과 마찬가지로 기밀성을 제공하지 않는다. +- 시크릿 API와 통신하는 애플리케이션을 배포할 때, + [RBAC](/docs/reference/access-authn-authz/rbac/)과 같은 + [인증 정책](/docs/reference/access-authn-authz/authorization/)을 사용하여 + 접근을 제한해야 한다. +- 쿠버네티스 API에서, 네임스페이스 내 시크릿에 대한 `watch` 와 `list` 요청은 매우 강력한 기능이다. + 시크릿 목록 조회를 가능하게 하면 + 클라이언트가 해당 네임스페이스에 있는 모든 시크릿의 값을 검사할 수도 있기 때문에 + 가능한 한 이러한 접근 권한을 주는 것은 피해야 한다. -### 위험 +### 클러스터 관리자를 위한 보안 추천 사항 - - API 서버에서 시크릿 데이터는 {{< glossary_tooltip term_id="etcd" >}}에 저장된다. - 따라서, - - 관리자는 클러스터 데이터에 대해 저장 시 암호화를 활성화해야 한다. (v1.13 이상 필요) - - 관리자는 etcd에 대한 접근을 admin 사용자로 제한해야 한다. - - 관리자는 더 이상 사용하지 않을 때 etcd에서 사용하는 디스크를 지우거나 폐기할 수 있다. - - 클러스터에서 etcd를 실행하는 경우, 관리자는 etcd peer-to-peer 통신에 대해 - SSL/TLS를 사용해야 한다. - - base64로 인코딩된 시크릿 데이터가 있는 매니페스트(JSON 또는 YAML) - 파일을 통해 시크릿을 구성하는 경우, 이 파일을 공유하거나 소스 리포지터리에 - 체크인하면 시크릿이 손상된다. Base64 인코딩은 암호화 방법이 _아니며_ - 일반 텍스트와 동일한 것으로 간주된다. - - 실수로 기록하거나 신뢰할 수 없는 상대방에게 전송하지 않는 것과 같이, - 애플리케이션은 볼륨에서 읽은 후에 시크릿 값을 보호해야 한다. - - 시크릿을 사용하는 파드를 생성할 수 있는 사용자는 해당 시크릿의 값도 볼 수 있다. - API 서버 정책이 해당 사용자가 시크릿을 읽을 수 있도록 허용하지 않더라도, 사용자는 - 시크릿을 노출하는 파드를 실행할 수 있다. +{{< caution >}} +시크릿을 사용하는 파드를 생성할 수 있는 사용자는 해당 시크릿의 값을 볼 수도 있다. +클러스터 정책에서 사용자가 직접 시크릿을 조회하는 것을 금지했더라도, +동일한 사용자가 시크릿을 노출하는 파드에 접근 권한을 가질 수 있다. +{{< /caution >}} + +- (쿠버네티스 API를 사용하여) 클러스터의 모든 시크릿을 감시(`watch`) 또는 나열(`list`)하는 권한을 제한하여, + 가장 특권이 있는 시스템 레벨의 컴포넌트에만 이 동작을 허용한다. +- 시크릿 API와 통신하는 애플리케이션을 배포할 때, + [RBAC](/docs/reference/access-authn-authz/rbac/)과 같은 + [인증 정책](/docs/reference/access-authn-authz/authorization/)을 사용하여 + 접근을 제한해야 한다. +- API 서버에서, (시크릿을 포함한) 오브젝트는 + {{< glossary_tooltip term_id="etcd" >}}에 저장된다. 그러므로 + - 클러스터 관리자만 etcd에 접근할 수 있도록 한다(읽기 전용 접근 포함) + - 시크릿 오브젝트에 대해 + [저장된 데이터 암호화(encryption at rest)](/docs/tasks/administer-cluster/encrypt-data/)를 활성화하여, + 이러한 시크릿의 데이터가 {{< glossary_tooltip term_id="etcd" >}}에 암호화되지 않은 상태로 저장되지 않도록 한다. + - etcd가 동작하던 장기 저장 장치를 더 이상 사용하지 않는다면 + 초기화 또는 파쇄하는 것을 검토한다. + - etcd 인스턴스가 여러 개라면, + etcd 피어 간 통신에 SSL/TLS를 사용하고 있는지 확인한다. ## {{% heading "whatsnext" %}} -- [`kubectl` 을 사용한 시크릿 관리](/ko/docs/tasks/configmap-secret/managing-secret-using-kubectl/)하는 방법 배우기 -- [구성 파일을 사용한 시크릿 관리](/ko/docs/tasks/configmap-secret/managing-secret-using-config-file/)하는 방법 배우기 -- [kustomize를 사용한 시크릿 관리](/ko/docs/tasks/configmap-secret/managing-secret-using-kustomize/)하는 방법 배우기 +- [`kubectl` 을 사용하여 시크릿 관리](/ko/docs/tasks/configmap-secret/managing-secret-using-kubectl/)하는 방법 배우기 +- [구성 파일을 사용하여 시크릿 관리](/ko/docs/tasks/configmap-secret/managing-secret-using-config-file/)하는 방법 배우기 +- [kustomize를 사용하여 시크릿 관리](/ko/docs/tasks/configmap-secret/managing-secret-using-kustomize/)하는 방법 배우기 - [API 레퍼런스](/docs/reference/kubernetes-api/config-and-storage-resources/secret-v1/)에서 `Secret`에 대해 읽기