인포레터에서 최신 DevOps 트렌드를 격주로 만나보세요!
머신 ID 문제 해결 가이드
이 페이지는 머신 ID를 설정할 때 발생할 수 있는 문제에 대한 해결 단계를 제공합니다.
봇이 "생성 불일치"로 인해 인증서를 갱신하지 못했습니다
증상
봇은 다음과 같은 오류를 기록합니다:
ERROR: renewable cert generation mismatch: stored=3, presented=2
봇의 후속 연결 시도는 다음과 같은 오류를 볼 수 있습니다:
ERROR: failed direct dial to auth server: auth API: access denied [00]
"\tauth API: access denied [00], failed dial to auth server through reverse tunnel: Get \"https://teleport.cluster.local/v2/configuration/name\": Get \"https://example.com:3025/webapi/find\": x509: cannot validate certificate for example.com because it doesn't contain any IP SANs"
"\tGet \"https://teleport.cluster.local/v2/configuration/name\": Get \"https://example.com:3025/webapi/find\": x509: cannot validate certificate for example.com because it doesn't contain any IP SANs"
특히, auth API: access denied
메시지에 주의하십시오.
자체 호스팅된 Teleport 배포에서 Teleport Auth 서비스는 추가 컨텍스트를 제공할 것입니다:
[AUTH] WARN lock targeting User:"bot-example" is in force: The bot user "bot-example" has been locked due to a certificate generation mismatch, possibly indicating a stolen certificate. auth/apiserver.go:224
설명
이것은 token
가입 방법을 사용하는 봇에만 적용되며, 이는 일회용 공유 비밀을
사용합니다. GitHub, AWS IAM 등과 같은 공급자 특정 가입 방법은 다른 봇
인스턴스가 token
가입을 사용하지 않는 한 이와 같은 방식으로 잠기지 않습니다.
머신 ID(토큰 기반 가입 사용)는 잠재적으로 도난당한 갱신 가능한 인증서를 감지하기 위해 인증서 생성 카운터를 사용합니다. 봇이 새 갱신 가능한 인증서를 가져올 때마다 Auth 서비스는 카운터를 증가시키고 백엔드에 저장하며 인증서에 카운터의 복사본을 포함합니다.
여러분의 봇 인증서에 포함된 카운터가 Teleport의 Auth 서버에 저장된 카운터와 일치하지 않으면 갱신이 실패하고 봇 사용자는 자동으로 잠김을 당합니다.
갱신 가능한 인증서는 기본적으로 /var/lib/teleport/bot
에 있는 봇의 내부 데이터 디렉토리에 독점적으로 저장됩니다. 동일한 내부 데이터 디렉토리를 사용하는 여러 봇이 시작되거나 이 내부 데이터가 여러 tbot
프로세스 간에 공유되는 경우 우연히 이 문제를 유발할 수 있습니다.
또한, 봇이 새로 갱신된 인증서를 저장하지 못하고(예: 파일 시스템 오류로 인해) 충돌하는 경우, 이전 인증서를 사용하여 갱신을 시도하고 잠금을 유발할 수 있습니다.
해결 방법
봇의 잠금을 해제하기 전에 위에서 설명한 두 가지 시나리오 중 하나가 적용되는지 확인하십시오. 인증서가 도난당한 경우, 해결해야 할 보안 문제가 있을 수 있습니다.
그렇지 않은 경우, 먼저 내부 데이터 디렉토리를 사용하는 tbot
프로세스가 하나만 있는지 확인하십시오. 여러 봇이 단일 시스템에서 실행될 수 있지만 각 봇에 대해 별도의 데이터 디렉토리를 구성해야 합니다.
또한 내부 데이터가 다른 노드와 공유되거나 복사되지 않도록 하십시오(예: 공유 NFS 볼륨을 통해). 노드 간에 인증서를 공유하려면 내부 데이터 디렉토리(기본적으로 /var/lib/teleport/bot
)가 아닌 대상 디렉토리(일반적으로 /opt/machine-id
)에서만 콘텐츠를 복사하거나 공유하십시오.
기본 원인을 해결한 후, 잠긴 봇을 재설정하기 위해 다음 단계를 따르십시오:
- 봇 사용자에 대한 잠금을 제거합니다.
- 새 봇 인스턴스를 생성하여 봇의 생성 카운터를 재설정합니다.
먼저 봇 사용자에 대한 잠금을 찾아서 제거합니다. 이 예에서는 봇의 이름이 example
이라고 가정하며, 이에 따라 bot-example
이라는 Teleport 사용자와 연결됩니다:
tctl get lockskind: lockmetadata: id: 1658359514703080513 name: 5cee949f-5203-4f3b-9805-dac35d798a16spec: message: The bot user "bot-example" has been locked due to a certificate generation mismatch, possibly indicating a stolen certificate. target: user: bot-exampleversion: v2tctl rm lock/5cee949f-5203-4f3b-9805-dac35d798a16
다음으로 tctl bots instances add
를 사용하여 기존 봇 example
에 대한 새 가입 토큰을 생성합니다:
tctl bots instances add example
마지막으로, 새로운 토큰으로 로컬 tbot
인스턴스를 재구성하고 다시 시작합니다. 이렇게 하면 새 토큰을 감지하고 내부 데이터 디렉토리를 자동으로 재설정합니다. 봇은 연결된 후 새 봇 인스턴스 UUID를 부여받고 생성 카운터가 재설정됩니다.
tbot
시작 시 "bad certificate error" 표시
증상
tbot
프로세스를 재시작하면 다음과 같은 로그가 출력됩니다:
INFO [TBOT] 봇 ID를 성공적으로 로드했습니다, 유효: after=2022-07-21T21:49:26Z, before=2022-07-21T22:50:26Z, duration=1h1m0s | kind=tls, renewable=true, disallow-reissue=false, roles=[bot-test], principals=[-teleport-internal-join], generation=2 tbot/tbot.go:281
ERRO [TBOT] ID가 만료되었습니다. 갱신이 실패할 가능성이 높습니다. (만료: 2022-07-21T22:50:26Z, 현재 시간: 2022-07-25T20:18:33Z) tbot/tbot.go:415
WARN [TBOT] 참고: ID가 영속 스토리지에서 로드되었으므로 온보딩 구성이 무시되었습니다. tbot/tbot.go:288
ERRO [TBOT] 터널 주소를 해결하지 못했습니다. Get "https://auth.example.com:3025/webapi/find": x509: auth.example.com의 인증서를 검증할 수 없습니다. IP SAN이 포함되어 있지 않기 때문입니다. reversetunnel/transport.go:90
ERRO [TBOT] 터널 주소를 해결하지 못했습니다. Get "https://auth.example.com:3025/webapi/find": x509: auth.example.com의 인증서를 검증할 수 없습니다. IP SAN이 포함되어 있지 않기 때문입니다. reversetunnel/transport.go:90
ERROR: 인증 서버에 직접 다이얼 실패: Get "https://teleport.cluster.local/v2/configuration/name": 원격 오류: tls: bad certificate
"\tGet \"https://teleport.cluster.local/v2/configuration/name\": 원격 오류: tls: bad certificate, 리버스 터널을 통해 인증 서버에 다이얼 실패: Get \"https://teleport.cluster.local/v2/configuration/name\": Get \"https://auth.example.com:3025/webapi/find\": x509: auth.example.com의 인증서를 검증할 수 없습니다. IP SAN이 포함되어 있지 않기 때문입니다."
"\tGet \"https://teleport.cluster.local/v2/configuration/name\": Get \"https://auth.example.com:3025/webapi/find\": x509: auth.example.com의 인증서를 검증할 수 없습니다. IP SAN이 포함되어 있지 않기 때문입니다."
특히 로그 행을 주의하십시오: "ID가 만료되었습니다. 갱신이 실패할 가능성이 높습니다."
설명
토큰으로 연결된 봇은 인증서가 만료되면 Teleport Auth Service에 다시 인증할 수 없습니다. 토큰 기반 조인에서(AWS IAM 및 기타 조인 방법과는 달리) 토큰은 한 번만 사용될 수 있으므로, 봇의 내부 인증서가 만료되면 연결할 수 없습니다.
봇의 ID가 만료되면 Auth Service에 있는 봇과 관련된 특정 파라미터를 초기화하고 새로운 조인 토큰을 발급해야 합니다. 이를 가장 간단하게 수행하는 방법은 봇을 제거하고 재생성하여 모든 서버 측 데이터를 제거하고 새로운 조인 토큰을 발급하는 것입니다.
해결 방법
tctl bots instances add
를 사용하여 봇에 대한 새로운 일회용 토큰을 생성하십시오:
tctl bots instances add example
결과로 생성된 조인 토큰을 기존 봇 구성에 복사합니다—--token
CLI 플래그 또는 tbot.yaml
의 onboarding.token
파라미터에—그리고 봇을 재시작합니다. 그러면 새로운 토큰을 감지하고 정상적으로 클러스터에 재조인합니다.
SSH 연결 실패 ssh: handshake failed: ssh: unable to authenticate
증상
노드에 SSH로 연결을 시도할 때, 다음과 같은 오류로 연결이 실패합니다:
ssh -F /opt/machine-id/ssh_config bob@node.example.comERROR: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
ERROR: unable to execute tshexecuting `tsh proxy`exit status 1
kex_exchange_identification: 연결이 원격 호스트에 의해 닫혔습니다.UNKNOWN 포트 65535에서 연결이 닫혔습니다.
특히 ssh: unable to authenticate
메시지에 주목하십시오.
설명
SSH 인증서에 명시된 사용자 목록에 없는 사용자로 노드에 로그인하려고 시도할 때 이러한 문제가 발생할 수 있습니다.
tbot
로그를 통해 해당 출력에 대한 대리 인증서가 갱신된 로그 메시지를 확인하여 이를 검증할 수 있습니다.
다음 예제에서 /opt/machine-id
에 나열된 유일한 주체는 access
역할을 통해 alice
입니다:
INFO [TBOT] /opt/machine-id 디렉터리에 대한 대리 인증서를 성공적으로 갱신했습니다, 유효: after=2022-07-21T21:49:26Z, before=2022-07-21T22:50:26Z, duration=1h1m0s | kind=tls, renewable=false, disallow-reissue=true, roles=[access], principals=[alice -teleport-internal-join], generation=0 tbot/renew.go:630
그러나 SSH 명령은 bob
으로 로그인하려고 했습니다.
해결 방법
봇 아이덴티티가 요청된 사용자로 로그인할 수 있도록 다음 중 하나의 조치를 취하십시오:
- 허용된 사용자로 로그인하도록 SSH 명령 변경
access
역할을 수정하여alice
주체를 허용bob
주체를 통한 로그인을 부여하는 역할 추가
역할이 추가되거나 수정된 경우 변경 사항이 적용되도록 인증서를 갱신해야 합니다. 봇은 갱신 간격(기본값: 20분) 후에 인증서를 자동으로 갱신하지만, 다음 명령으로 즉시 갱신을 트리거할 수 있습니다:
# systemd를 사용하는 경우 프로세스를 재시작할 수 있습니다:
systemctl restart machine-id# 또는 `tbot` 에 직접 reload 신호를 보낼 수 있습니다:
pkill -sigusr1 tbot
데이터베이스 요청이 database "example" not found
로 실패하나 데이터베이스는 존재함
증상
Database Access 인증서를 요청하면 인증서 요청이 다음과 같은 오류로 실패합니다:
ERROR: /opt/machine-id에 대한 대리 인증서를 생성하지 못했습니다: database "example" not found
database "example" not found
그러나 해당 데이터베이스는 존재하며 일반 사용자가 tsh
를 통해 확인할 수 있습니다:
tsh db lsName Description Allowed Users Labels Connect---------- ----------- ------------- ------- -------example [alice] env=dev
설명
정상적인 Teleport 사용자가 아닌 머신 ID 봇 사용자는 최소한의 Teleport RBAC 권한만 부여받으며 기본적으로 데이터베이스를 보고 나열할 수 없습니다. 역할을 통해 권한이 부여되지 않는 한 볼 수 없습니다.
해결 방법
Machine ID Database Access Guide를 참조하여 오류에 나열된 출력에 대한 데이터베이스 권한을 제공하는 역할이 부여되었는지 확인하십시오.
예를 들어 다음 예제 역할의 rules
섹션을 확인하십시오:
kind: role
version: v5
metadata:
name: machine-id-db
spec:
allow:
db_labels:
"*": "*"
db_names: [example]
db_users: [alice]
rules:
- resources: [db_server, db]
verbs: [read, list]
봇이 적어도 이러한 RBAC 규칙을 부여받는 역할이 있어야 합니다. 원하신다면, tctl
을 통해 봇 역할을 확인하여 필요한 rules
가 부여되었는지 확인할 수 있습니다:
tctl get role/machine-id-db
역할에 데이터베이스 권한이 누락된 경우, 텍스트 편집기에서 수정할 수 있습니다:
tctl edit role/machine-id-db
역할을 수정한 후, 파일을 저장하고 닫아 변경 사항을 적용하십시오.
기본적으로 출력(예: /opt/machine-id
)은 tctl bots add --roles=...
를 통해 봇에 제공되는 모든 역할을 부여받지만, tbot.yaml
의 roles: ...
매개변수를 사용하여 이러한 역할의 하위 집합만 부여할 수 있습니다.
권한이 예상치 않게 누락된 경우, tbot.yaml
이 데이터베이스 역할을 요청하는지 확인하십시오. 기본 동작에 의존하거나 역할을 roles: ...
목록에 추가하여 요청해야 합니다.
문제가 해결된 후, 업데이트된 역할이 적용되도록 tbot
클라이언트를 재시작하거나 다시 로드하십시오.
봇이 처음에 역할을 부여받지 못한 경우, 가장 간단한 해결 방법은 봇을 삭제하고 재생성하는 것입니다. 이때 --roles=...
플래그에 역할을 포함시켜야 합니다:
tctl bots rm exampletctl bots add example --roles=foo,bar,machine-id-db
대상 kubernetes_secret: identity-output
는 exec 플러그인 모드에서 디렉토리여야 합니다
기본적으로 쿠버네티스 아이덴티티를 출력할 때, tbot
은 쿠버네티스 exec 플러그인을 사용하여 항상 자격 증명의 최신 버전을 제공합니다.
하지만 쿠버네티스 아이덴티티를 쿠버네티스 비밀로 출력할 때는, exec
플러그인의 사용을 비활성화하는 것이 중요합니다. 이를 위해 disable_exec_plugin: true
를 출력에 추가해야 합니다. 이는 짧은 수명의 자격 증명이 포함된 정적 kubeconfig
파일이 대신 작성됨을 의미합니다:
outputs:
- type: kubernetes
# 자격 증명이 접근을 허용할 쿠버네티스 클러스터의 이름을 지정하십시오.
kubernetes_cluster: example-k8s-cluster
# 쿠버네티스 비밀로 쿠버네티스 아이덴티티를 출력할 때 필수입니다.
disable_exec_plugin: true
destination:
type: kubernetes_secret
# 이 가이드에서는 identity-output이 비밀 이름으로 사용됩니다.
# 이를 사용자 지정할 수 있습니다. 여러 출력을 동일한
# 대상으로 공유할 수 없습니다.
name: identity-output
disable_exec_plugin
플래그를 추가하지 않으면 경고 메시지가 표시됩니다:
Destination kubernetes_secret: identity-output must be a directory in exec plugin mode
.
분할 DNS 프록시를 위한 tbot
구성
프록시 서비스를 내부 및 외부 주소와 같은 두 개의 서로 다른 DNS 이름으로 접근할 수 있도록 배포한 경우, 이러한 주소 중 하나를 사용하도록 구성된 tbot
이 다른 주소를 사용하려고 시도하여 연결이 실패할 수 있습니다.
이는 tbot
이 연결할 때 사용할 표준 주소를 결정하기 위해 프록시 서비스에서 노출된 자동 구성 엔드포인트를 쿼리하기 때문입니다.
이 문제를 해결하려면 tbot
프로세스의 환경에 TBOT_USE_PROXY_ADDR=yes
변수를 설정하십시오. 이는 tbot
이 명시적으로 제공한 주소를 우선 사용하도록 구성합니다. 이는 Teleport 클러스터에 TLS 라우팅/다중화가 활성화된 경우에만 올바르게 작동합니다.