시크릿
시크릿 (Secrets)
Secret은 비밀번호, 토큰, 키 같은 소량의 민감한 데이터를 포함하는 객체예요. 그러한 정보는 그렇지 않으면 파드 사양이나 컨테이너 이미지에 넣을 수도 있어요. Secret을 사용한다는 것은 기밀 데이터를 애플리케이션 코드에 포함할 필요가 없다는 뜻이에요.
Secret은 그것을 사용하는 파드와 독립적으로 생성될 수 있기 때문에 파드를 생성, 보기, 편집하는 워크플로 중에 Secret(과 그 데이터)이 노출될 위험이 더 적어요. Kubernetes와 클러스터에서 실행되는 애플리케이션은 또한 민감한 데이터를 비휘발성 스토리지에 쓰지 않는 것 같은 추가 예방 조치를 Secret에 취할 수 있어요.
Secret은 ConfigMap과 유사하지만 기밀 데이터를 보유하도록 특별히 의도됐어요.
Kubernetes Secret은 기본적으로 API 서버의 기본 데이터 저장소(etcd)에 암호화되지 않은 상태로 저장돼요. API 접근 권한이 있는 누구나 Secret을 검색하거나 수정할 수 있고, etcd에 접근할 수 있는 누구도 그럴 수 있어요. 게다가 네임스페이스에서 파드를 생성하도록 인가된 누구나 그 접근을 사용해 그 네임스페이스의 어떤 Secret도 읽을 수 있어요. 여기에는 Deployment를 생성할 수 있는 능력 같은 간접 접근도 포함돼요.
Secret을 안전하게 사용하려면 최소한 다음 단계를 취해요:
- Secret에 대해 저장 데이터 암호화(Encryption at Rest)를 활성화해요.
- Secret에 대한 최소 권한 접근으로 RBAC 규칙을 활성화하거나 구성해요.
- Secret 접근을 특정 컨테이너로 제한해요.
- 외부 Secret 저장소 프로바이더 사용을 고려해요.
Secret의 보안을 관리하고 개선하기 위한 더 많은 지침은 Kubernetes Secret 모범 사례를 참고해요.
자세한 내용은 Secret의 정보 보안을 참고해요.
출처: 문서
본문
Secret의 용도 (Uses for Secrets)
Secret을 다음과 같은 목적에 사용할 수 있어요:
Kubernetes 컨트롤 플레인도 Secret을 사용해요. 예를 들어 부트스트랩 토큰 Secret은 노드 등록을 자동화하는 데 도움이 되는 메커니즘이에요.
사용 사례: 시크릿 볼륨의 dotfile (#use-case-dotfiles-in-a-secret-volume)
점으로 시작하는 키를 정의해 데이터를 "숨길" 수 있어요. 이 키는 dotfile 또는 "숨겨진" 파일을 나타내요. 예를 들어 다음 Secret이 secret-volume이라는 볼륨에 마운트되면 볼륨은 .secret-file이라는 단일 파일을 포함하고, dotfile-test-container는 /etc/secret-volume/.secret-file 경로에 이 파일을 가질 거예요.
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: registry.k8s.io/busybox
command:
- ls
- "-l"
- "/etc/secret-volume"
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
사용 사례: 파드의 한 컨테이너에만 보이는 Secret (#use-case-secret-visible-to-one-container-in-a-pod)
HTTP 요청을 처리하고, 복잡한 비즈니스 로직을 수행하고, 그다음 HMAC으로 일부 메시지에 서명해야 하는 프로그램을 고려해요. 복잡한 애플리케이션 로직이 있기 때문에 서버에 눈에 띄지 않는 원격 파일 읽기 악용이 있을 수 있고, 공격자에게 개인 키를 노출할 수 있어요.
이것은 두 컨테이너의 두 프로세스로 나눌 수 있어요: 사용자 상호작용과 비즈니스 로직을 처리하지만 개인 키를 볼 수 없는 프론트엔드 컨테이너, 그리고 개인 키를 볼 수 있고 프론트엔드의 간단한 서명 요청(예: localhost 네트워킹으로)에 응답하는 서명자 컨테이너.
이 분할 접근 방식으로 공격자는 이제 애플리케이션 서버가 파일을 읽게 하는 것보다 더 어려울 수 있는 다소 임의적인 작업을 하도록 속여야 해요.
Secret의 대안 (#alternatives-to-secrets)
기밀 데이터를 보호하기 위해 Secret을 사용하는 대신, 대안 중에서 선택할 수 있어요.
다음은 옵션 중 일부예요:
- 클라우드 네이티브 컴포넌트가 같은 Kubernetes 클러스터에서 실행되고 있다고 아는 다른 애플리케이션에 인증해야 한다면 ServiceAccount와 그 토큰을 사용해 클라이언트를 식별할 수 있어요.
- 클러스터 내부 또는 외부에서 실행할 수 있는, 민감한 데이터를 관리하는 서드파티 도구가 있어요. 예를 들어 클라이언트가 올바르게 인증하면(예: ServiceAccount 토큰으로) Secret을 공개하는 파드가 HTTPS로 접근하는 서비스가 있어요.
- 인증의 경우 X.509 인증서용 커스텀 서명자를 구현하고, CertificateSigningRequests를 사용해 그 커스텀 서명자가 필요한 파드에 인증서를 발급하게 할 수 있어요.
- 디바이스 플러그인을 사용해 노드 로컬 암호화 하드웨어를 특정 파드에 노출할 수 있어요. 예를 들어 대역 외로 구성된 TPM(Trusted Platform Module)을 제공하는 노드에 신뢰할 수 있는 파드를 스케줄링할 수 있어요.
그러한 옵션 중 두 가지 이상을, Secret 객체 자체를 사용하는 옵션을 포함해 조합할 수도 있어요.
예를 들어: 외부 서비스에서 단기 세션 토큰을 가져온 다음 그 단기 세션 토큰을 기반으로 Secret을 만드는 운영자를 구현(또는 배포)해요. 클러스터에서 실행되는 파드는 세션 토큰을 사용할 수 있고, 운영자가 그것들이 유효함을 보장해요. 이 분리는 세션 토큰을 발급하고 새로 고치는 정확한 메커니즘을 인식하지 못하는 파드를 실행할 수 있다는 뜻이에요.
Secret의 유형 (Types of Secret)
Secret을 만들 때 Secret 리소스의 type 필드 또는 일부 동등한 kubectl 명령줄 플래그(사용 가능한 경우)를 사용해 그 유형을 지정할 수 있어요. Secret 유형은 Secret 데이터의 프로그래밍 방식 처리를 용이하게 하는 데 사용돼요.
Kubernetes는 몇 가지 일반적인 사용 시나리오에 대한 여러 내장 유형을 제공해요. 이 유형들은 수행되는 검증과 Kubernetes가 그것들에 부과하는 제약이 다양해요.
| 내장 유형 | 용도 |
|---|---|
| Opaque | 임의의 사용자 정의 데이터 |
| kubernetes.io/service-account-token | ServiceAccount 토큰 |
| kubernetes.io/dockercfg | 직렬화된 ~/.dockercfg 파일 |
| kubernetes.io/dockerconfigjson | 직렬화된 ~/.docker/config.json 파일 |
| kubernetes.io/basic-auth | 기본 인증용 자격 증명 |
| kubernetes.io/ssh-auth | SSH 인증용 자격 증명 |
| kubernetes.io/tls | TLS 클라이언트 또는 서버용 데이터 |
| bootstrap.kubernetes.io/token | 부트스트랩 토큰 데이터 |
Secret 객체의 type 값으로 비어 있지 않은 문자열을 할당해 자체 Secret 유형을 정의하고 사용할 수 있어요(빈 문자열은 Opaque 유형으로 처리됨).
Kubernetes는 유형 이름에 어떤 제약도 부과하지 않아요. 하지만 내장 유형 중 하나를 사용한다면 그 유형에 대해 정의된 모든 요구 사항을 충족해야 해요.
공개용 Secret 유형을 정의한다면 관례를 따르고 /로 구분해 도메인 이름을 이름 앞에 구조화해요. 예: cloud-hosting.example.net/cloud-api-credentials.
Opaque Secret (#opaque-secrets)
Secret 매니페스트에서 유형을 명시적으로 지정하지 않으면 Opaque가 기본 Secret 유형이에요. kubectl로 Secret을 만들 때는 Opaque Secret 유형을 나타내기 위해 generic 하위 명령을 사용해야 해요. 예를 들어 다음 명령은 Opaque 유형의 빈 Secret을 만들어요:
kubectl create secret generic empty-secret
kubectl get secret empty-secret
출력은 다음과 같아요:
NAME TYPE DATA AGE
empty-secret Opaque 0 2m6s
DATA 열은 Secret에 저장된 데이터 항목의 수를 보여줘요. 이 경우 0은 빈 Secret을 만들었음을 의미해요.
ServiceAccount 토큰 Secret (#serviceaccount-token-secrets)
kubernetes.io/service-account-token 유형의 Secret은 ServiceAccount를 식별하는 토큰 자격 증명을 저장하는 데 사용돼요. 이것은 파드에 장기간 유효한 ServiceAccount 자격 증명을 제공하는 레거시 메커니즘이에요.
Kubernetes v1.22 이상에서 권장되는 접근 방식은 대신 TokenRequest API를 사용해 단기간 유효하고 자동으로 회전되는 ServiceAccount 토큰을 얻는 것이에요. 다음 방법으로 이러한 단기 토큰을 얻을 수 있어요:
- TokenRequest API를 직접 호출하거나
kubectl같은 API 클라이언트를 사용해 호출해요. 예를 들어 kubectl create token 명령을 사용할 수 있어요. - 파드 매니페스트의 projected volume에 마운트된 토큰을 요청해요. Kubernetes가 토큰을 만들고 파드에 마운트해요. 토큰은 그것이 마운트된 파드가 삭제될 때 자동으로 무효화돼요. 자세한 내용은 ServiceAccount 토큰 프로젝션을 사용한 파드 시작을 참고해요.
이 Secret 유형을 사용할 때는 kubernetes.io/service-account.name 어노테이션이 기존 ServiceAccount 이름으로 설정되어 있는지 확인해야 해요. ServiceAccount와 Secret 객체를 모두 만든다면 ServiceAccount 객체를 먼저 만들어야 해요.
Secret이 생성된 후 Kubernetes 컨트롤러가 kubernetes.io/service-account.uid 어노테이션과, data 필드의 token 키 같은 다른 필드를 채우며, 이 토큰 키는 인증 토큰으로 채워져요.
다음 예시 구성은 ServiceAccount 토큰 Secret을 선언해요:
apiVersion: v1
kind: Secret
metadata:
name: secret-sa-sample
annotations:
kubernetes.io/service-account.name: "sa-name"
type: kubernetes.io/service-account-token
data:
extra: YmFyCg==
Secret을 만든 후 Kubernetes가 data 필드의 token 키를 채울 때까지 기다려요.
ServiceAccount가 어떻게 동작하는지에 대한 더 많은 정보는 ServiceAccount 문서를 참고해요. 파드 내에서 ServiceAccount 자격 증명을 참조하는 방법에 대한 정보는 Pod의 automountServiceAccountToken 필드와 serviceAccountName 필드도 확인할 수 있어요.
Docker config Secret (#docker-config-secrets)
컨테이너 이미지 레지스트리 접근을 위한 자격 증명을 저장하는 Secret을 만들 때는 그 Secret에 대해 다음 유형 값 중 하나를 사용해야 해요:
kubernetes.io/dockercfg: Docker 명령줄을 구성하는 레거시 형식인 직렬화된~/.dockercfg를 저장해요. Secretdata필드는 값이 base64 인코딩된~/.dockercfg파일의 내용인.dockercfg키를 포함해요.kubernetes.io/dockerconfigjson:~/.dockercfg의 새 형식인~/.docker/config.json파일과 같은 형식 규칙을 따르는 직렬화된 JSON을 저장해요. Secretdata필드는 값이 base64 인코딩된~/.docker/config.json파일의 내용인.dockerconfigjson키를 포함해야 해요.
아래는 kubernetes.io/dockercfg 유형의 Secret 예시예요:
apiVersion: v1
kind: Secret
metadata:
name: secret-dockercfg
type: kubernetes.io/dockercfg
data:
.dockercfg: |
eyJhdX...9fQo=
매니페스트로 Docker config Secret을 만들 때 API 서버는 예상 키가 data 필드에 존재하는지 확인하고, 제공된 값이 유효한 JSON으로 파싱될 수 있는지 검증해요. API 서버는 JSON이 실제로 Docker config 파일인지는 검증하지 않아요.
또한 kubectl을 사용해 컨테이너 레지스트리 접근용 Secret을 만들 수 있어요. 예를 들어 Docker 구성 파일이 없을 때:
kubectl create secret docker-registry secret-tiger-docker \
[email protected] \
--docker-username=tiger \
--docker-password=pass1234 \
--docker-server=my-registry.example:5000
이 명령은 kubernetes.io/dockerconfigjson 유형의 Secret을 만들어요.
그 새 Secret에서 .data.dockerconfigjson 필드를 검색하고 데이터를 디코드해요:
kubectl get secret secret-tiger-docker -o jsonpath='{.data.*}' | base64 -d
출력은 다음 JSON 문서(또한 유효한 Docker 구성 파일임)와 동등해요:
{
"auths": {
"my-registry.example:5000": {
"username": "tiger",
"password": "pass1234",
"email": "[email protected]",
"auth": "dGlnZXI6cGFzczEyMzQ="
}
}
}
거기의 auth 값은 base64 인코딩돼 있어요. 그것은 난독화되었지만 비밀은 아니에요. 그 Secret을 읽을 수 있는 누구나 레지스트리 접근 베어러 토큰을 알 수 있어요.
자격 증명 프로바이더를 사용해 온디맨드로 풀 시크릿을 동적이고 안전하게 제공하는 것이 좋아요.
기본 인증 Secret (#basic-authentication-secret)
kubernetes.io/basic-auth 유형은 기본 인증에 필요한 자격 증명을 저장하기 위해 제공돼요. 이 Secret 유형을 사용할 때 Secret의 data 필드는 다음 두 키 중 하나를 포함해야 해요:
username: 인증용 사용자 이름password: 인증용 비밀번호 또는 토큰
위 두 키의 두 값 모두 base64 인코딩된 문자열이에요. 대안으로 Secret 매니페스트의 stringData 필드를 사용해 일반 텍스트 내용을 제공할 수 있어요.
다음 매니페스트는 기본 인증 Secret의 예시예요:
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin # required field for kubernetes.io/basic-auth
password: t0p-Secret # required field for kubernetes.io/basic-auth
기본 인증 Secret 유형은 편의를 위해서만 제공돼요. 기본 인증에 사용되는 자격 증명에 대해 Opaque 유형을 만들 수 있어요. 하지만 정의되고 공개된 Secret 유형(kubernetes.io/basic-auth)을 사용하면 다른 사람이 여러분의 Secret의 목적을 이해하는 데 도움이 되고, 기대할 키 이름에 대한 관례를 설정해요.
SSH 인증 Secret (#ssh-authentication-secrets)
내장 유형 kubernetes.io/ssh-auth는 SSH 인증에 사용되는 데이터를 저장하기 위해 제공돼요. 이 Secret 유형을 사용할 때 사용할 SSH 자격 증명으로 data(또는 stringData) 필드에 ssh-privatekey 키-값 쌍을 지정해야 해요.
다음 매니페스트는 SSH 공개/개인 키 인증에 사용되는 Secret의 예시예요:
apiVersion: v1
kind: Secret
metadata:
name: secret-ssh-auth
type: kubernetes.io/ssh-auth
data:
# the data is abbreviated in this example
ssh-privatekey: |
UG91cmluZzYlRW1vdGljb24lU2N1YmE=
SSH 인증 Secret 유형은 편의를 위해서만 제공돼요. SSH 인증에 사용되는 자격 증명에 대해 Opaque 유형을 만들 수 있어요. 하지만 정의되고 공개된 Secret 유형(kubernetes.io/ssh-auth)을 사용하면 다른 사람이 여러분의 Secret의 목적을 이해하는 데 도움이 되고, 기대할 키 이름에 대한 관례를 설정해요. Kubernetes API는 이 유형의 Secret에 필요한 키가 설정되었는지 검증해요.
주의: SSH 개인 키는 저장 데이터 암호화가 활성화된 Kubernetes 클러스터에서만 사용해야 해요. 활성화되지 않은 클러스터에서는 공격자가 해당 Secret에 대한 API 접근 권한을 얻으면 SSH 개인 키를 검색할 수 있어요.
TLS Secret (#tls-secrets)
kubernetes.io/tls Secret 유형은 일반적으로 TLS에 사용되는 인증서와 연관된 키를 저장하기 위한 것이에요.
TLS Secret의 한 가지 일반적인 용도는 Ingress의 전송 중 암호화를 구성하는 것이지만, 다른 리소스와 함께 또는 워크로드에서 직접 사용할 수도 있어요. 이 유형의 Secret을 사용할 때 API 서버가 각 키의 값을 실제로 검증하지는 않지만, tls.key와 tls.crt 키가 Secret 구성의 data(또는 stringData) 필드에 제공되어야 해요.
stringData를 사용하는 대신 data 필드를 사용해 base64 인코딩된 인증서와 개인 키를 제공할 수 있어요. 자세한 내용은 Secret 이름과 데이터의 제약을 참고해요.
다음 YAML은 TLS Secret에 대한 예시 구성을 포함해요:
apiVersion: v1
kind: Secret
metadata:
name: secret-tls
type: kubernetes.io/tls
data:
# values are base64 encoded, which obscures them but does NOT provide
# any useful level of confidentiality
# Replace the following values with your own base64-encoded certificate and key.
tls.crt: "REPLACE_WITH_BASE64_CERT"
tls.key: "REPLACE_WITH_BASE64_KEY"
TLS Secret 유형은 편의를 위해서만 제공돼요. TLS 인증에 사용되는 자격 증명에 대해 Opaque 유형을 만들 수 있어요. 하지만 정의되고 공개된 Secret 유형(kubernetes.io/tls)을 사용하면 프로젝트에서 Secret 형식의 일관성을 보장하는 데 도움이 돼요. API 서버는 이 유형의 Secret에 필요한 키가 설정되었는지 검증해요.
kubectl을 사용해 TLS Secret을 만들려면 tls 하위 명령을 사용해요:
kubectl create secret tls my-tls-secret \
--cert=path/to/cert/file \
--key=path/to/key/file
공개/개인 키 쌍은 미리 존재해야 해요. --cert의 공개 키 인증서는 .PEM 인코딩이어야 하고 --key의 주어진 개인 키와 일치해야 해요.
부트스트랩 토큰 Secret (#bootstrap-token-secrets)
bootstrap.kubernetes.io/token Secret 유형은 노드 부트스트랩 과정 중에 사용되는 토큰을 위한 것이에요. 잘 알려진 ConfigMap에 서명하는 데 사용되는 토큰을 저장해요.
부트스트랩 토큰 Secret은 보통 kube-system 네임스페이스에 생성되고 <token-id>가 토큰 ID의 6자 문자열인 bootstrap-token-<token-id> 형식으로 이름이 지정돼요.
Kubernetes 매니페스트로서 부트스트랩 토큰 Secret은 다음과 같을 수 있어요:
apiVersion: v1
kind: Secret
metadata:
name: bootstrap-token-5emitj
namespace: kube-system
type: bootstrap.kubernetes.io/token
data:
auth-extra-groups: c3lzdGVtOmJvb3RzdHJhcHBlcnM6a3ViZWFkbTpkZWZhdWx0LW5vZGUtdG9rZW4=
expiration: MjAyMC0wOS0xM1QwNDozOToxMFo=
token-id: NWVtaXRq
token-secret: a3E0Z2lodnN6emduMXAwcg==
usage-bootstrap-authentication: dHJ1ZQ==
usage-bootstrap-signing: dHJ1ZQ==
부트스트랩 토큰 Secret은 data 아래에 다음 키를 지정해요:
token-id: 토큰 식별자로 사용되는 임의의 6자 문자열. 필수.token-secret: 실제 토큰 Secret으로 사용되는 임의의 16자 문자열. 필수.description: 토큰이 무엇에 사용되는지 설명하는 사람이 읽을 수 있는 문자열. 선택.expiration: 토큰이 만료되어야 하는 시기를 지정하는, RFC3339(https://datatracker.ietf.org/doc/html/rfc3339)를 사용한 절대 UTC 시간. 선택.usage-bootstrap-<usage>: 부트스트랩 토큰의 추가 용도를 나타내는 불리언 플래그.auth-extra-groups:system:bootstrappers그룹에 추가로 인증될 그룹 이름의 쉼표로 구분된 목록.
대안으로 Secret의 stringData 필드에 base64 인코딩하지 않고 값을 제공할 수 있어요:
apiVersion: v1
kind: Secret
metadata:
# Note how the Secret is named
name: bootstrap-token-5emitj
# A bootstrap token Secret usually resides in the kube-system namespace
namespace: kube-system
type: bootstrap.kubernetes.io/token
stringData:
auth-extra-groups: "system:bootstrappers:kubeadm:default-node-token"
expiration: "2020-09-13T04:39:10Z"
# This token ID is used in the name
token-id: "5emitj"
token-secret: "kq4gihvszzgn1p0r"
# This token can be used for authentication
usage-bootstrap-authentication: "true"
# and it can be used for signing
usage-bootstrap-signing: "true"
Secret 사용하기 (Working with Secrets)
Secret 만들기 (#creating-a-secret)
Secret을 만드는 데는 몇 가지 옵션이 있어요:
- kubectl 사용
- 구성 파일 사용
- Kustomize 도구 사용
Secret 이름과 데이터의 제약 (#restriction-names-data)
Secret 객체의 이름은 유효한 DNS 하위 도메인 이름이어야 해요.
Secret의 구성 파일을 만들 때 data 및/또는 stringData 필드를 지정할 수 있어요. data와 stringData 필드는 선택 사항이에요. data 필드의 모든 키의 값은 base64 인코딩된 문자열이어야 해요. base64 문자열로의 변환이 바람직하지 않다면 대신 임의의 문자열을 값으로 받아들이는 stringData 필드를 지정할 수 있어요.
data와 stringData의 키는 영숫자 문자, -, _, .로 구성되어야 해요. stringData 필드의 모든 키-값 쌍은 내부적으로 data 필드로 병합돼요. 키가 data와 stringData 필드 모두에 나타나면 stringData 필드에 지정된 값이 우선해요.
크기 제한 (#restriction-data-size)
개별 Secret은 크기가 1MiB로 제한돼요. 이것은 API 서버와 kubelet 메모리를 소진할 수 있는 매우 큰 Secret의 생성을 막기 위한 것이에요. 하지만 더 작은 Secret을 많이 만드는 것도 메모리를 소진할 수 있어요. 리소스 쿼터를 사용해 네임스페이스의 Secret(또는 다른 리소스) 수를 제한할 수 있어요.
Secret 편집 (#editing-a-secret)
Immutable이 아닌 한 기존 Secret을 편집할 수 있어요. Secret을 편집하려면 다음 방법 중 하나를 사용해요:
Kustomize 도구를 사용해 Secret의 데이터를 편집할 수도 있어요(/docs/tasks/configmap-secret/managing-secret-using-kustomize/#edit-secret). 하지만 이 방법은 편집된 데이터로 새 Secret 객체를 만들어요.
Secret을 어떻게 만들었는지와 Secret이 파드에서 어떻게 사용되는지에 따라 기존 Secret 객체에 대한 업데이트는 그 데이터를 사용하는 파드에 자동으로 전파돼요. 더 많은 정보는 파드에서 파일로 Secret 사용 섹션을 참고해요.
Secret 사용 (#using-a-secret)
Secret은 데이터 볼륨으로 마운트되거나 환경 변수로 노출되어 파드의 컨테이너가 사용할 수 있어요. Secret은 또한 파드에 직접 노출되지 않고 시스템의 다른 부분에서 사용될 수도 있어요. 예를 들어 Secret은 시스템의 다른 부분이 여러분을 대신해 외부 시스템과 상호작용하는 데 사용해야 하는 자격 증명을 보유할 수 있어요.
Secret 볼륨 소스는 지정된 객체 참조가 실제로 Secret 유형의 객체를 가리키는지 확인하기 위해 검증돼요. 따라서 Secret은 그것에 의존하는 파드가 생성되기 전에 생성되어야 해요.
Secret을 가져올 수 없으면(존재하지 않거나 API 서버에 대한 일시적 연결 부족 때문일 수 있음) kubelet은 그 파드 실행을 주기적으로 재시도해요. kubelet은 또한 Secret을 가져오는 문제의 세부 사항을 포함한 Event를 그 파드에 대해 보고해요.
선택적 Secret (#restriction-secret-must-exist)
파드에서 Secret을 참조할 때 다음 예시에서처럼 Secret을 optional로 표시할 수 있어요. 선택적 Secret이 존재하지 않으면 Kubernetes는 그것을 무시해요.
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: true
기본적으로 Secret은 필수예요. 모든 비선택적 Secret을 사용할 수 있을 때까지 파드의 어떤 컨테이너도 시작되지 않아요.
파드가 비선택적 Secret의 특정 키를 참조하고 그 Secret이 존재하지만 명명된 키가 없으면 파드는 시작 중에 실패해요.
파드에서 파일로 Secret 사용 (#using-secrets-as-files-from-a-pod)
파드의 Secret에서 데이터에 접근하려면 한 가지 방법은 Kubernetes가 그 Secret의 값을 파드의 하나 이상의 컨테이너 파일시스템 내부의 파일로 사용 가능하게 하는 것이에요.
지침은 볼륨을 통해 시크릿 데이터에 접근 권한이 있는 파드 만들기를 참고해요.
볼륨이 Secret의 데이터를 포함하고 그 Secret이 업데이트되면 Kubernetes는 이것을 추적하고 궁극적으로 일관된 접근 방식으로 볼륨의 데이터를 업데이트해요.
kubelet은 해당 노드의 파드 볼륨에 사용되는 Secret의 현재 키와 값의 캐시를 유지해요. kubelet이 캐시된 값에서 변경을 감지하는 방식을 구성할 수 있어요. kubelet 구성의 configMapAndSecretChangeDetectionStrategy 필드는 kubelet이 사용하는 전략을 제어해요. 기본 전략은 Watch예요.
Secret에 대한 업데이트는 API watch 메커니즘(기본값), 정의된 time-to-live가 있는 캐시 기반, 또는 각 kubelet 동기화 루프에서 클러스터 API 서버에서 폴링 중 하나로 전파될 수 있어요.
그 결과, Secret이 업데이트된 순간부터 새 키가 파드에 프로젝션되는 순간까지의 총 지연은 kubelet 동기화 주기 + 캐시 전파 지연만큼 길 수 있어요. 여기서 캐시 전파 지연은 선택한 캐시 유형에 따라 달라져요(이전 단락에 나열된 것과 같은 순서로: watch 전파 지연, 구성된 캐시 TTL, 또는 직접 폴링의 경우 0).
환경 변수로 Secret 사용 (#using-secrets-as-environment-variables)
파드의 환경 변수에서 Secret을 사용하려면:
- 파드 사양의 각 컨테이너에 대해 사용하려는 각 Secret 키에 대한 환경 변수를
env[].valueFrom.secretKeyRef필드에 추가해요. - 프로그램이 지정된 환경 변수에서 값을 찾도록 이미지 및/또는 명령줄을 수정해요.
지침은 Secret 데이터를 사용해 컨테이너 환경 변수 정의를 참고해요.
파드의 환경 변수 이름에 허용되는 문자 범위가 제한된다는 점을 유의하는 것이 중요해요(/docs/tasks/inject-data-application/define-environment-variable-container/#using-environment-variables-inside-of-your-config). 어떤 키가 규칙을 충족하지 않으면 그 키는 컨테이너에서 사용 가능하게 되지 않지만 파드는 시작이 허용돼요.
컨테이너 이미지 풀 Secret (#using-imagepullsecrets)
비공개 리포지토리에서 컨테이너 이미지를 가져오려면 각 노드의 kubelet이 그 리포지토리에 인증할 방법이 필요해요. image pull Secret을 구성해 이것을 가능하게 할 수 있어요. 이 Secret은 파드 수준에서 구성돼요.
imagePullSecrets 사용 (#using-imagepullsecrets-1)
imagePullSecrets 필드는 같은 네임스페이스의 Secret에 대한 참조 목록이에요. imagePullSecrets를 사용해 Docker(또는 다른) 이미지 레지스트리 비밀번호를 포함하는 Secret을 kubelet에 전달할 수 있어요. kubelet은 이 정보를 사용해 파드를 대신해 비공개 이미지를 가져와요. imagePullSecrets 필드에 대한 더 많은 정보는 PodSpec API를 참고해요.
컨테이너 이미지 문서에서 imagePullSecrets를 지정하는 방법을 배울 수 있어요.
imagePullSecrets를 수동으로 만들고 ServiceAccount에서 이것을 참조할 수 있어요. 그 ServiceAccount로 생성되거나 기본적으로 그 ServiceAccount로 생성되는 모든 파드는 자신의 imagePullSecrets 필드가 서비스 계정의 그것으로 설정되게 될 거예요. 그 과정에 대한 자세한 설명은 서비스 계정에 ImagePullSecrets 추가를 참고해요.
정적 파드와 함께 Secret 사용 (#restriction-static-pod)
정적 파드에서는 ConfigMap이나 Secret을 사용할 수 없어요.
불변 Secret (#secret-immutable)
Kubernetes는 특정 Secret(및 ConfigMap)을 immutable로 표시하게 해줘요. 기존 Secret의 데이터 변경을 방지하는 것에는 다음과 같은 이점이 있어요:
- 애플리케이션 중단을 일으킬 수 있는 우발적(또는 원치 않는) 업데이트로부터 보호함.
- (Secret을 많이 사용하는 클러스터의 경우 - 최소 수만 개의 고유 Secret 대 파드 마운트) 불변 Secret으로 전환하면 kube-apiserver에 대한 부하를 크게 줄여 클러스터 성능을 향상시킴. kubelet은 불변으로 표시된 어떤 Secret에도 watch를 유지할 필요가 없음.
Secret을 불변으로 표시 (#secret-immutable-create)
immutable 필드를 true로 설정해 불변 Secret을 만들 수 있어요. 예:
apiVersion: v1
kind: Secret
metadata: ...
data: ...
immutable: true
또한 기존 변경 가능한 Secret을 업데이트해 불변으로 만들 수도 있어요.
Secret을 불변으로 만들면 그 데이터를 변경하려는 어떤 시도(또는 immutable: false로 되돌리는 것)도 실패한다는 점에 유의해요. Secret을 삭제하고 새로 만들어야 해요.
Secret의 정보 보안 (#information-security-for-secrets)
ConfigMap과 Secret이 비슷하게 동작하지만 Kubernetes는 Secret 객체에 대해 추가 보호를 적용해요.
Secret은 종종 중요도 스펙트럼에 걸친 값을 보유하며, 그중 많은 것이 Kubernetes 내부(예: 서비스 계정 토큰)와 외부 시스템에서 권한 상승을 일으킬 수 있어요. 개별 앱이 상호작용할 것으로 기대하는 Secret의 힘을 추론할 수 있더라도, 같은 네임스페이스의 다른 앱이 그 가정을 무효화할 수 있어요.
인가 구성은 네임스페이스 내에서 Secret 데이터에 어떻게 접근할 수 있는지에 영향을 미쳐요. 예를 들어 Secret에 대한 list 또는 watch 권한을 부여하면 주체가 그 네임스페이스의 모든 Secret 데이터를 읽을 수 있는데, 그 파드가 명시적으로 참조하는 Secret만이 아니라요. 워크로드가 기능하는 데 필요한 최소 권한 집합으로 접근을 제한하고, 관리 목적으로 필요하지 않으면 cluster-admin 같은 광범위한 역할을 부여하는 것을 피해요.
또한 인가 문서를 참고해요.
Secret은 해당 노드의 파드가 필요할 때만 노드로 전송돼요. Secret을 파드에 마운트할 때 kubelet은 기밀 데이터가 영구 스토리지에 기록되지 않도록 데이터의 사본을 tmpfs에 저장해요. Secret에 의존하는 파드가 삭제되면 kubelet은 Secret의 기밀 데이터의 로컬 사본을 삭제해요.
파드에는 여러 컨테이너가 있을 수 있어요. 기본적으로 정의한 컨테이너는 기본 ServiceAccount와 관련 Secret에만 접근할 수 있어요. 다른 Secret에 대한 접근을 제공하려면 환경 변수를 명시적으로 정의하거나 컨테이너에 볼륨을 매핑해야 해요.
같은 노드에 여러 파드의 Secret이 있을 수 있어요. 하지만 파드가 요청한 Secret만 그 컨테이너 내에서 잠재적으로 보일 수 있어요. 따라서 한 파드는 다른 파드의 Secret에 접근할 수 없어요.
Secret에 대한 최소 권한 접근 구성 (#configure-least-privilege-access-to-secrets)
Secret 주변의 보안 조치를 강화하려면 별도의 네임스페이스를 사용해 마운트된 시크릿에 대한 접근을 격리해요.
시크릿 자체를 특별한 시스템으로 취급하고 사용자에게 secret 접근 권한을 부여할 때 최소 권한 전략을 사용하지 않으면 RBAC로 사용자가 시크릿에 접근하는 것을 차단해도 환경 변수를 통해 컨테이너에서 시크릿을 읽을 수 있습니다. 어떤 사용자에게 secret 접근을 허용하면 관리자도 사용자가 그 비밀을 알고 있다고 가정해야 합니다. 시크릿이 수명 주기 중 어느 시점에 사용자에게 노출되면, 그 키를 사용하는 리소스를 어디에나 배포할 수 있으며, RBAC가 이를 중지하지 않습니다.
다음 단계 (What's next)
- Secret의 보안을 관리하고 개선하기 위한 지침은 Kubernetes Secret 모범 사례를 참고해요.
- kubectl로 Secret 관리 배우기
- 구성 파일로 Secret 관리 배우기
- kustomize로 Secret 관리 배우기
- Secret에 대한 API 참조 읽기