InfoGrab Docs

머신 및 워크로드 아이덴티티 문제 해결 가이드

요약

이 페이지는 머신 및 워크로드 아이덴티티(MWI)를 설정할 때 발생할 수 있는 문제에 대한 해결 단계를 제공합니다. 봇이 다음과 같은 오류를 기록합니다: 봇의 후속 연결 시도에서 다음과 같은 오류가 발생할 수 있습니다:

이 페이지는 머신 및 워크로드 아이덴티티(MWI)를 설정할 때 발생할 수 있는 문제에 대한 해결 단계를 제공합니다.

봇이 "generation mismatch"로 인해 인증서 갱신에 실패했습니다#

증상#

봇이 다음과 같은 오류를 기록합니다:

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 Service도 추가 컨텍스트를 제공합니다:

[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

설명#

Note

이는 일회성 공유 비밀을 사용하는 token 조인 방법을 사용하는 봇에만 적용됩니다. GitHub, AWS IAM 등과 같은 제공업체별 조인 방법은 봇의 다른 인스턴스가 token 조인을 사용하지 않는 한 이런 방식으로 잠기지 않습니다.

머신 및 워크로드 아이덴티티(토큰 기반 조인)는 인증서 생성 카운터를 사용하여 잠재적으로 도난된 갱신 가능한 인증서를 감지합니다. 봇이 새 갱신 가능한 인증서를 가져올 때마다, Auth Service는 카운터를 증가시키고 백엔드에 저장하며 인증서에 카운터 복사본을 내장합니다.

봇 인증서에 내장된 카운터가 Teleport의 Auth Service에 저장된 카운터와 일치하지 않으면, 갱신이 실패하고 봇 사용자는 자동으로 잠금 처리됩니다.

갱신 가능한 인증서는 봇의 내부 데이터 디렉터리(기본값: /var/lib/teleport/bot)에만 저장됩니다. 여러 봇이 동일한 내부 데이터 디렉터리를 사용하거나 이 내부 데이터가 여러 tbot 프로세스 간에 공유되는 경우 우발적으로 발생할 수 있습니다.

또한 봇이 새로 갱신된 인증서를 저장하는 데 실패하고(예: 파일시스템 오류로 인해) 크래시되면, 이전 인증서로 갱신을 시도하여 잠금을 발생시킵니다.

해결 방법#

봇을 잠금 해제하기 전에, 위에서 설명한 두 가지 시나리오 중 하나가 해당되는지 확인하세요. 인증서가 도난당한 경우, 해결해야 할 기본 보안 우려사항이 있을 수 있습니다.

그렇지 않다면, 먼저 하나의 tbot 프로세스만 내부 데이터 디렉터리를 사용하도록 하세요. 단일 시스템에서 여러 봇을 실행할 수 있지만, 각각에 대해 별도의 데이터 디렉터리를 구성해야 합니다.

또한, 공유 NFS 볼륨과 같은 방식으로 내부 데이터가 다른 노드와 공유되거나 복사되지 않도록 하세요. 노드 간에 인증서를 공유하려면, 내부 데이터 디렉터리(기본값: /var/lib/teleport/bot) 대신 대상 디렉터리(보통 /opt/machine-id)의 내용만 복사하거나 공유하세요.

근본 원인을 해결한 후, 다음 단계에 따라 잠긴 봇을 재설정하세요:

  1. 봇 사용자의 잠금 제거
  2. 새 봇 인스턴스를 생성하여 봇의 생성 카운터 재설정

잠금을 제거하려면, 먼저 봇 사용자를 대상으로 하는 잠금을 찾아 제거하세요. 이 예에서는 봇 이름이 example이고, 연결된 Teleport 사용자 이름은 bot-example이라고 가정합니다:

$ tctl get locks
kind: lock
metadata:
  id: 1658359514703080513
  name: 5cee949f-5203-4f3b-9805-dac35d798a16
spec:
  message: The bot user "bot-example" has been locked due to a certificate generation
    mismatch, possibly indicating a stolen certificate.
  target:
    user: bot-example
version: v2

$ tctl 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]      Successfully loaded bot identity, valid: 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]      Identity has expired. The renewal is likely to fail. (expires: 2022-07-21T22:50:26Z, current time: 2022-07-25T20:18:33Z) tbot/tbot.go:415
WARN [TBOT]      Note: onboarding config ignored as identity was loaded from persistent storage tbot/tbot.go:288
ERRO [TBOT]      Failed to resolve tunnel address Get "https://auth.example.com:3025/webapi/find": x509: cannot validate certificate for auth.example.com because it doesn't contain any IP SANs reversetunnel/transport.go:90
ERRO [TBOT]      Failed to resolve tunnel address Get "https://auth.example.com:3025/webapi/find": x509: cannot validate certificate for auth.example.com because it doesn't contain any IP SANs reversetunnel/transport.go:90
ERROR: failed direct dial to auth server: Get "https://teleport.cluster.local/v2/configuration/name": remote error: tls: bad certificate
"\tGet \"https://teleport.cluster.local/v2/configuration/name\": remote error: tls: bad certificate, failed dial to auth server through reverse tunnel: Get \"https://teleport.cluster.local/v2/configuration/name\": Get \"https://auth.example.com:3025/webapi/find\": x509: cannot validate certificate for auth.example.com because it doesn't contain any IP SANs"
"\tGet \"https://teleport.cluster.local/v2/configuration/name\": Get \"https://auth.example.com:3025/webapi/find\": x509: cannot validate certificate for auth.example.com because it doesn't contain any IP SANs"

특히, "Identity has expired. The renewal is likely to fail." 로그 라인에 주목하세요.

설명#

토큰 조인 봇은 인증서가 만료된 후 Teleport Auth Service에 재인증할 수 없습니다. 토큰 기반 조인(AWS IAM 및 다른 조인 방법과 달리)의 토큰은 한 번만 사용할 수 있으므로, 봇의 내부 인증서가 만료되면 연결할 수 없습니다.

봇의 ID가 만료되면, Auth Service에서 봇과 관련된 특정 매개변수를 재설정하고 새 조인 토큰을 발급해야 합니다. 이를 수행하는 가장 간단한 방법은 봇을 삭제하고 다시 만드는 것으로, 모든 서버 측 데이터를 삭제하고 새 조인 토큰을 발급합니다.

해결 방법#

tctl bots instances add를 사용하여 봇에 대한 새 일회성 토큰을 생성합니다:

$ tctl bots instances add example

결과 조인 토큰을 기존 봇 구성(--token CLI 플래그 또는 tbot.yamlonboarding.token 매개변수)에 복사하고 봇을 재시작합니다. 새 토큰을 감지하고 정상적으로 클러스터에 재조인합니다.

SSH 연결이 ssh: handshake failed: ssh: unable to authenticate로 실패합니다#

증상#

SSH를 통해 노드에 연결하려 할 때, 다음과 같은 오류와 함께 연결이 실패합니다:

$ ssh -F /opt/machine-id/ssh_config bob@node.example.com
ERROR: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain

ERROR: unable to execute tsh
executing `tsh proxy`
exit status 1

kex_exchange_identification: Connection closed by remote host
Connection closed by UNKNOWN port 65535

특히, ssh: unable to authenticate 메시지에 주목하세요.

설명#

SSH 인증서의 주체로 나열되지 않은 사용자로 노드에 로그인하려 할 때 발생할 수 있습니다.

tbot 로그를 확인하고 일치하는 서비스에 대한 위임 인증서가 갱신되었을 때의 로그 메시지를 찾아 이를 확인할 수 있습니다.

다음 예에서, /opt/machine-id의 ID에 대해 나열된 유일한 주체는 (access 역할을 통해) alice입니다:

INFO [TBOT]      Successfully renewed impersonated certificates for directory /opt/machine-id, valid: 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으로 로그인을 시도했습니다.

해결 방법#

다음 중 하나의 작업을 통해 봇 ID가 요청된 사용자로 로그인할 수 있도록 하세요:

  • SSH 명령을 허용된 사용자로 로그인하도록 변경
  • access 역할을 수정하여 bob 주체를 허용
  • bob 주체를 통한 로그인을 허용하는 역할 추가

역할을 추가하거나 수정하면, 변경 사항이 적용되려면 인증서를 갱신해야 합니다. 봇은 갱신 간격(기본값 20분) 후에 자동으로 인증서를 갱신하지만, tbot 프로세스를 재시작하거나 리로드 신호를 보내 즉시 갱신을 트리거할 수 있습니다:

## systemd를 사용하는 경우 프로세스를 재시작할 수 있습니다:
$ systemctl restart machine-id
## 또는 `tbot`에 직접 리로드 신호를 보낼 수 있습니다:
$ pkill -sigusr1 tbot

데이터베이스가 존재하지만 데이터베이스 요청이 database "example" not found로 실패합니다#

증상#

Teleport로 보호된 데이터베이스에 대한 인증서를 요청할 때, 인증서 요청이 다음과 같은 오류와 함께 실패합니다:

ERROR: Failed to generate impersonated certs for directory /opt/machine-id: database "example" not found
database "example" not found

그러나 데이터베이스가 존재하며 tsh를 통해 일반 사용자가 볼 수 있습니다:

$ tsh db ls
Name       Description Allowed Users Labels  Connect
---------- ----------- ------------- ------- -------
example                [alice]       env=dev

설명#

일반 Teleport 사용자와 달리, 머신 및 워크로드 아이덴티티 봇 사용자는 최소한의 Teleport RBAC 권한만 부여받으며, 하나 이상의 역할을 통해 권한이 부여되지 않는 한 기본적으로 데이터베이스를 조회하거나 나열할 수 없습니다.

해결 방법#

머신 및 워크로드 아이덴티티 데이터베이스 액세스 가이드에 따라, 오류에 나열된 출력 서비스에 데이터베이스 권한을 제공하는 하나 이상의 역할이 부여되었는지 확인하세요.

예를 들어, 다음 예시 역할의 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

역할을 편집한 다음 파일을 저장하고 닫아 변경 사항을 적용합니다.

Note

기본적으로, 출력 서비스(예: /opt/machine-id)에는 tctl bots add --roles=...를 통해 봇에 제공된 모든 역할이 부여되지만, tbot.yamlroles: ... 매개변수를 사용하여 이러한 역할의 일부만 부여할 수도 있습니다.

권한이 예기치 않게 누락된 경우, tbot.yaml이 데이터베이스 역할을 요청하는지 확인하세요. 기본 동작에 의존하거나 roles: ... 목록에 역할을 추가하여 확인할 수 있습니다.

수정 후, 업데이트된 역할이 적용되도록 tbot 클라이언트를 재시작하거나 리로드하세요.

봇에 역할이 처음에 부여되지 않은 경우, 가장 간단한 해결책은 봇을 삭제하고 --roles=... 플래그에 역할을 포함하여 다시 만드는 것입니다:

$ tctl bots rm example
$ tctl bots add example --roles=foo,bar,machine-id-db

Destination kubernetes_secret: identity-output은 exec 플러그인 모드에서 디렉터리여야 합니다#

기본적으로, Kubernetes ID를 출력할 때, tbot 출력은 항상 최신 버전의 자격 증명을 제공하기 위해 Kubernetes exec 플러그인을 사용합니다.

그러나 Kubernetes ID를 Kubernetes 시크릿에 출력할 때는 출력에 disable_exec_plugin: true를 추가하여 exec 플러그인 사용을 비활성화하는 것이 중요합니다. 이는 내장된 단기 자격 증명이 포함된 정적 kubeconfig 파일이 대신 작성됨을 의미합니다:

services:
  - type: kubernetes
    # 자격 증명이 액세스를 부여할 Kubernetes 클러스터 이름을 지정합니다.
    kubernetes_cluster: example-k8s-cluster
    # Kubernetes ID를 Kubernetes 시크릿에 출력할 때 필요합니다.
    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 이름을 통해 Proxy Service에 액세스할 수 있도록 배포한 경우, 하나의 주소를 사용하도록 구성된 tbot이 다른 주소를 사용하려 할 수 있으며 이로 인해 연결이 실패할 수 있습니다.

이는 tbot이 Proxy Service에서 노출된 자동 구성 엔드포인트를 쿼리하여 연결 시 사용할 표준 주소를 결정하기 때문입니다.

이를 수정하려면, tbot 프로세스의 환경에서 TBOT_USE_PROXY_ADDR=yes 변수를 설정하세요. 이렇게 하면 명시적으로 제공한 주소를 사용하도록 tbot이 구성됩니다. 이 기능은 Teleport 클러스터에 대해 TLS 라우팅/멀티플렉싱이 활성화된 경우에만 올바르게 작동합니다.

액세스 가능한 Teleport Proxy Service 없는 환경에서 tbot 사용#

기본적으로, identity 출력 서비스를 사용할 때, tbot 클라이언트는 사용 가능한 리프 클러스터를 포함하여 사용 가능한 Teleport 클러스터에 대한 정보를 가져오기 위해 Proxy Service를 쿼리합니다. 이는 사용 가능한 ssh_config를 생성하는 데 필요합니다.

auth_server 구성 옵션을 통해 Teleport Auth Service와 직접 통신하도록 tbot이 구성된 환경에서 실행 중이지만 Teleport Proxy Service와 통신할 수 없는 경우, ID 출력 서비스는 다음과 같은 오류와 함께 ssh_config 생성에 실패합니다:

2026-01-21T18:11:16.320-07:00 ERRO [TBOT:PROX] Failed to ping proxy error:[
ERROR REPORT:
Original Error: *url.Error Get "https://teleport.example.com:443/webapi/find": dial tcp 1.2.3.4:443: connect: connection refused
Stack Trace:
	github.com/gravitational/teleport/api@v0.0.0/client/webclient/webclient.go:167 github.com/gravitational/teleport/api/client/webclient.doWithFallback
	github.com/gravitational/teleport/api@v0.0.0/client/webclient/webclient.go:218 github.com/gravitational/teleport/api/client/webclient.findWithClient
	github.com/gravitational/teleport/api@v0.0.0/client/webclient/webclient.go:192 github.com/gravitational/teleport/api/client/webclient.Find
	github.com/gravitational/teleport/lib/tbot/internal/caching_proxy_pinger.go:104 github.com/gravitational/teleport/lib/tbot/internal.(*CachingProxyPinger).Ping
	github.com/gravitational/teleport/lib/tbot/services/identity/output.go:198 github.com/gravitational/teleport/lib/tbot/services/identity.(*OutputService).generate
	github.com/gravitational/teleport/lib/tbot/internal/loop.go:161 github.com/gravitational/teleport/lib/tbot/internal.RunOnInterval
	github.com/gravitational/teleport/lib/tbot/services/identity/output.go:113 github.com/gravitational/teleport/lib/tbot/services/identity.(*OutputService).Run
	github.com/gravitational/teleport/lib/tbot/bot/bot.go:103 github.com/gravitational/teleport/lib/tbot/bot.(*Bot).Run.func2
	golang.org/x/sync@v0.19.0/errgroup/errgroup.go:93 golang.org/x/sync/errgroup.(*Group).Go.func1
	runtime/asm_amd64.s:1693 runtime.goexit
User Message: Get "https://teleport.example.com:443/webapi/find": dial tcp 1.2.3.4:443: connect: connection refused] internal/caching_proxy_pinger.go:110

많은 경우 다운스트림 애플리케이션이 작동하려면 ssh_config가 필요하므로, 이것은 예상된 동작입니다. 그러나 ssh_config가 필요하지 않은 경우, ID 출력 서비스의 설정에서 ssh_config: "off"를 설정하여 비활성화할 수 있습니다:

version: v2
auth_server: teleport.example.com:3025
onboarding:
  token: '...snip...'
  join_method: token
storage:
  type: directory
  path: ./storage
services:
  - type: identity
    destination:
      type: directory
      path: ./destination
    ssh_config: "off"

원하는 경우, ID 출력 서비스 구성 옵션에 대해 더 읽어볼 수 있습니다.

다른 tbot 서비스도 Proxy Service에 연결하려 할 수 있으며, 차단된 경우 유사하게 실패할 수 있습니다. 최상의 호환성을 위해, tbot 클라이언트는 Auth Service에 직접 연결하도록 구성된 경우에도 일반적으로 Proxy Service에 대한 네트워크 액세스를 받아야 합니다.

머신 및 워크로드 아이덴티티 문제 해결 가이드

원문 보기
요약

이 페이지는 머신 및 워크로드 아이덴티티(MWI)를 설정할 때 발생할 수 있는 문제에 대한 해결 단계를 제공합니다. 봇이 다음과 같은 오류를 기록합니다: 봇의 후속 연결 시도에서 다음과 같은 오류가 발생할 수 있습니다:

이 페이지는 머신 및 워크로드 아이덴티티(MWI)를 설정할 때 발생할 수 있는 문제에 대한 해결 단계를 제공합니다.

봇이 "generation mismatch"로 인해 인증서 갱신에 실패했습니다#

증상#

봇이 다음과 같은 오류를 기록합니다:

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 Service도 추가 컨텍스트를 제공합니다:

[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

설명#

Note

이는 일회성 공유 비밀을 사용하는 token 조인 방법을 사용하는 봇에만 적용됩니다. GitHub, AWS IAM 등과 같은 제공업체별 조인 방법은 봇의 다른 인스턴스가 token 조인을 사용하지 않는 한 이런 방식으로 잠기지 않습니다.

머신 및 워크로드 아이덴티티(토큰 기반 조인)는 인증서 생성 카운터를 사용하여 잠재적으로 도난된 갱신 가능한 인증서를 감지합니다. 봇이 새 갱신 가능한 인증서를 가져올 때마다, Auth Service는 카운터를 증가시키고 백엔드에 저장하며 인증서에 카운터 복사본을 내장합니다.

봇 인증서에 내장된 카운터가 Teleport의 Auth Service에 저장된 카운터와 일치하지 않으면, 갱신이 실패하고 봇 사용자는 자동으로 잠금 처리됩니다.

갱신 가능한 인증서는 봇의 내부 데이터 디렉터리(기본값: /var/lib/teleport/bot)에만 저장됩니다. 여러 봇이 동일한 내부 데이터 디렉터리를 사용하거나 이 내부 데이터가 여러 tbot 프로세스 간에 공유되는 경우 우발적으로 발생할 수 있습니다.

또한 봇이 새로 갱신된 인증서를 저장하는 데 실패하고(예: 파일시스템 오류로 인해) 크래시되면, 이전 인증서로 갱신을 시도하여 잠금을 발생시킵니다.

해결 방법#

봇을 잠금 해제하기 전에, 위에서 설명한 두 가지 시나리오 중 하나가 해당되는지 확인하세요. 인증서가 도난당한 경우, 해결해야 할 기본 보안 우려사항이 있을 수 있습니다.

그렇지 않다면, 먼저 하나의 tbot 프로세스만 내부 데이터 디렉터리를 사용하도록 하세요. 단일 시스템에서 여러 봇을 실행할 수 있지만, 각각에 대해 별도의 데이터 디렉터리를 구성해야 합니다.

또한, 공유 NFS 볼륨과 같은 방식으로 내부 데이터가 다른 노드와 공유되거나 복사되지 않도록 하세요. 노드 간에 인증서를 공유하려면, 내부 데이터 디렉터리(기본값: /var/lib/teleport/bot) 대신 대상 디렉터리(보통 /opt/machine-id)의 내용만 복사하거나 공유하세요.

근본 원인을 해결한 후, 다음 단계에 따라 잠긴 봇을 재설정하세요:

  1. 봇 사용자의 잠금 제거
  2. 새 봇 인스턴스를 생성하여 봇의 생성 카운터 재설정

잠금을 제거하려면, 먼저 봇 사용자를 대상으로 하는 잠금을 찾아 제거하세요. 이 예에서는 봇 이름이 example이고, 연결된 Teleport 사용자 이름은 bot-example이라고 가정합니다:

$ tctl get locks
kind: lock
metadata:
  id: 1658359514703080513
  name: 5cee949f-5203-4f3b-9805-dac35d798a16
spec:
  message: The bot user "bot-example" has been locked due to a certificate generation
    mismatch, possibly indicating a stolen certificate.
  target:
    user: bot-example
version: v2

$ tctl 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]      Successfully loaded bot identity, valid: 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]      Identity has expired. The renewal is likely to fail. (expires: 2022-07-21T22:50:26Z, current time: 2022-07-25T20:18:33Z) tbot/tbot.go:415
WARN [TBOT]      Note: onboarding config ignored as identity was loaded from persistent storage tbot/tbot.go:288
ERRO [TBOT]      Failed to resolve tunnel address Get "https://auth.example.com:3025/webapi/find": x509: cannot validate certificate for auth.example.com because it doesn't contain any IP SANs reversetunnel/transport.go:90
ERRO [TBOT]      Failed to resolve tunnel address Get "https://auth.example.com:3025/webapi/find": x509: cannot validate certificate for auth.example.com because it doesn't contain any IP SANs reversetunnel/transport.go:90
ERROR: failed direct dial to auth server: Get "https://teleport.cluster.local/v2/configuration/name": remote error: tls: bad certificate
"\tGet \"https://teleport.cluster.local/v2/configuration/name\": remote error: tls: bad certificate, failed dial to auth server through reverse tunnel: Get \"https://teleport.cluster.local/v2/configuration/name\": Get \"https://auth.example.com:3025/webapi/find\": x509: cannot validate certificate for auth.example.com because it doesn't contain any IP SANs"
"\tGet \"https://teleport.cluster.local/v2/configuration/name\": Get \"https://auth.example.com:3025/webapi/find\": x509: cannot validate certificate for auth.example.com because it doesn't contain any IP SANs"

특히, "Identity has expired. The renewal is likely to fail." 로그 라인에 주목하세요.

설명#

토큰 조인 봇은 인증서가 만료된 후 Teleport Auth Service에 재인증할 수 없습니다. 토큰 기반 조인(AWS IAM 및 다른 조인 방법과 달리)의 토큰은 한 번만 사용할 수 있으므로, 봇의 내부 인증서가 만료되면 연결할 수 없습니다.

봇의 ID가 만료되면, Auth Service에서 봇과 관련된 특정 매개변수를 재설정하고 새 조인 토큰을 발급해야 합니다. 이를 수행하는 가장 간단한 방법은 봇을 삭제하고 다시 만드는 것으로, 모든 서버 측 데이터를 삭제하고 새 조인 토큰을 발급합니다.

해결 방법#

tctl bots instances add를 사용하여 봇에 대한 새 일회성 토큰을 생성합니다:

$ tctl bots instances add example

결과 조인 토큰을 기존 봇 구성(--token CLI 플래그 또는 tbot.yamlonboarding.token 매개변수)에 복사하고 봇을 재시작합니다. 새 토큰을 감지하고 정상적으로 클러스터에 재조인합니다.

SSH 연결이 ssh: handshake failed: ssh: unable to authenticate로 실패합니다#

증상#

SSH를 통해 노드에 연결하려 할 때, 다음과 같은 오류와 함께 연결이 실패합니다:

$ ssh -F /opt/machine-id/ssh_config bob@node.example.com
ERROR: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain

ERROR: unable to execute tsh
executing `tsh proxy`
exit status 1

kex_exchange_identification: Connection closed by remote host
Connection closed by UNKNOWN port 65535

특히, ssh: unable to authenticate 메시지에 주목하세요.

설명#

SSH 인증서의 주체로 나열되지 않은 사용자로 노드에 로그인하려 할 때 발생할 수 있습니다.

tbot 로그를 확인하고 일치하는 서비스에 대한 위임 인증서가 갱신되었을 때의 로그 메시지를 찾아 이를 확인할 수 있습니다.

다음 예에서, /opt/machine-id의 ID에 대해 나열된 유일한 주체는 (access 역할을 통해) alice입니다:

INFO [TBOT]      Successfully renewed impersonated certificates for directory /opt/machine-id, valid: 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으로 로그인을 시도했습니다.

해결 방법#

다음 중 하나의 작업을 통해 봇 ID가 요청된 사용자로 로그인할 수 있도록 하세요:

  • SSH 명령을 허용된 사용자로 로그인하도록 변경
  • access 역할을 수정하여 bob 주체를 허용
  • bob 주체를 통한 로그인을 허용하는 역할 추가

역할을 추가하거나 수정하면, 변경 사항이 적용되려면 인증서를 갱신해야 합니다. 봇은 갱신 간격(기본값 20분) 후에 자동으로 인증서를 갱신하지만, tbot 프로세스를 재시작하거나 리로드 신호를 보내 즉시 갱신을 트리거할 수 있습니다:

## systemd를 사용하는 경우 프로세스를 재시작할 수 있습니다:
$ systemctl restart machine-id
## 또는 `tbot`에 직접 리로드 신호를 보낼 수 있습니다:
$ pkill -sigusr1 tbot

데이터베이스가 존재하지만 데이터베이스 요청이 database "example" not found로 실패합니다#

증상#

Teleport로 보호된 데이터베이스에 대한 인증서를 요청할 때, 인증서 요청이 다음과 같은 오류와 함께 실패합니다:

ERROR: Failed to generate impersonated certs for directory /opt/machine-id: database "example" not found
database "example" not found

그러나 데이터베이스가 존재하며 tsh를 통해 일반 사용자가 볼 수 있습니다:

$ tsh db ls
Name       Description Allowed Users Labels  Connect
---------- ----------- ------------- ------- -------
example                [alice]       env=dev

설명#

일반 Teleport 사용자와 달리, 머신 및 워크로드 아이덴티티 봇 사용자는 최소한의 Teleport RBAC 권한만 부여받으며, 하나 이상의 역할을 통해 권한이 부여되지 않는 한 기본적으로 데이터베이스를 조회하거나 나열할 수 없습니다.

해결 방법#

머신 및 워크로드 아이덴티티 데이터베이스 액세스 가이드에 따라, 오류에 나열된 출력 서비스에 데이터베이스 권한을 제공하는 하나 이상의 역할이 부여되었는지 확인하세요.

예를 들어, 다음 예시 역할의 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

역할을 편집한 다음 파일을 저장하고 닫아 변경 사항을 적용합니다.

Note

기본적으로, 출력 서비스(예: /opt/machine-id)에는 tctl bots add --roles=...를 통해 봇에 제공된 모든 역할이 부여되지만, tbot.yamlroles: ... 매개변수를 사용하여 이러한 역할의 일부만 부여할 수도 있습니다.

권한이 예기치 않게 누락된 경우, tbot.yaml이 데이터베이스 역할을 요청하는지 확인하세요. 기본 동작에 의존하거나 roles: ... 목록에 역할을 추가하여 확인할 수 있습니다.

수정 후, 업데이트된 역할이 적용되도록 tbot 클라이언트를 재시작하거나 리로드하세요.

봇에 역할이 처음에 부여되지 않은 경우, 가장 간단한 해결책은 봇을 삭제하고 --roles=... 플래그에 역할을 포함하여 다시 만드는 것입니다:

$ tctl bots rm example
$ tctl bots add example --roles=foo,bar,machine-id-db

Destination kubernetes_secret: identity-output은 exec 플러그인 모드에서 디렉터리여야 합니다#

기본적으로, Kubernetes ID를 출력할 때, tbot 출력은 항상 최신 버전의 자격 증명을 제공하기 위해 Kubernetes exec 플러그인을 사용합니다.

그러나 Kubernetes ID를 Kubernetes 시크릿에 출력할 때는 출력에 disable_exec_plugin: true를 추가하여 exec 플러그인 사용을 비활성화하는 것이 중요합니다. 이는 내장된 단기 자격 증명이 포함된 정적 kubeconfig 파일이 대신 작성됨을 의미합니다:

services:
  - type: kubernetes
    # 자격 증명이 액세스를 부여할 Kubernetes 클러스터 이름을 지정합니다.
    kubernetes_cluster: example-k8s-cluster
    # Kubernetes ID를 Kubernetes 시크릿에 출력할 때 필요합니다.
    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 이름을 통해 Proxy Service에 액세스할 수 있도록 배포한 경우, 하나의 주소를 사용하도록 구성된 tbot이 다른 주소를 사용하려 할 수 있으며 이로 인해 연결이 실패할 수 있습니다.

이는 tbot이 Proxy Service에서 노출된 자동 구성 엔드포인트를 쿼리하여 연결 시 사용할 표준 주소를 결정하기 때문입니다.

이를 수정하려면, tbot 프로세스의 환경에서 TBOT_USE_PROXY_ADDR=yes 변수를 설정하세요. 이렇게 하면 명시적으로 제공한 주소를 사용하도록 tbot이 구성됩니다. 이 기능은 Teleport 클러스터에 대해 TLS 라우팅/멀티플렉싱이 활성화된 경우에만 올바르게 작동합니다.

액세스 가능한 Teleport Proxy Service 없는 환경에서 tbot 사용#

기본적으로, identity 출력 서비스를 사용할 때, tbot 클라이언트는 사용 가능한 리프 클러스터를 포함하여 사용 가능한 Teleport 클러스터에 대한 정보를 가져오기 위해 Proxy Service를 쿼리합니다. 이는 사용 가능한 ssh_config를 생성하는 데 필요합니다.

auth_server 구성 옵션을 통해 Teleport Auth Service와 직접 통신하도록 tbot이 구성된 환경에서 실행 중이지만 Teleport Proxy Service와 통신할 수 없는 경우, ID 출력 서비스는 다음과 같은 오류와 함께 ssh_config 생성에 실패합니다:

2026-01-21T18:11:16.320-07:00 ERRO [TBOT:PROX] Failed to ping proxy error:[
ERROR REPORT:
Original Error: *url.Error Get "https://teleport.example.com:443/webapi/find": dial tcp 1.2.3.4:443: connect: connection refused
Stack Trace:
	github.com/gravitational/teleport/api@v0.0.0/client/webclient/webclient.go:167 github.com/gravitational/teleport/api/client/webclient.doWithFallback
	github.com/gravitational/teleport/api@v0.0.0/client/webclient/webclient.go:218 github.com/gravitational/teleport/api/client/webclient.findWithClient
	github.com/gravitational/teleport/api@v0.0.0/client/webclient/webclient.go:192 github.com/gravitational/teleport/api/client/webclient.Find
	github.com/gravitational/teleport/lib/tbot/internal/caching_proxy_pinger.go:104 github.com/gravitational/teleport/lib/tbot/internal.(*CachingProxyPinger).Ping
	github.com/gravitational/teleport/lib/tbot/services/identity/output.go:198 github.com/gravitational/teleport/lib/tbot/services/identity.(*OutputService).generate
	github.com/gravitational/teleport/lib/tbot/internal/loop.go:161 github.com/gravitational/teleport/lib/tbot/internal.RunOnInterval
	github.com/gravitational/teleport/lib/tbot/services/identity/output.go:113 github.com/gravitational/teleport/lib/tbot/services/identity.(*OutputService).Run
	github.com/gravitational/teleport/lib/tbot/bot/bot.go:103 github.com/gravitational/teleport/lib/tbot/bot.(*Bot).Run.func2
	golang.org/x/sync@v0.19.0/errgroup/errgroup.go:93 golang.org/x/sync/errgroup.(*Group).Go.func1
	runtime/asm_amd64.s:1693 runtime.goexit
User Message: Get "https://teleport.example.com:443/webapi/find": dial tcp 1.2.3.4:443: connect: connection refused] internal/caching_proxy_pinger.go:110

많은 경우 다운스트림 애플리케이션이 작동하려면 ssh_config가 필요하므로, 이것은 예상된 동작입니다. 그러나 ssh_config가 필요하지 않은 경우, ID 출력 서비스의 설정에서 ssh_config: "off"를 설정하여 비활성화할 수 있습니다:

version: v2
auth_server: teleport.example.com:3025
onboarding:
  token: '...snip...'
  join_method: token
storage:
  type: directory
  path: ./storage
services:
  - type: identity
    destination:
      type: directory
      path: ./destination
    ssh_config: "off"

원하는 경우, ID 출력 서비스 구성 옵션에 대해 더 읽어볼 수 있습니다.

다른 tbot 서비스도 Proxy Service에 연결하려 할 수 있으며, 차단된 경우 유사하게 실패할 수 있습니다. 최상의 호환성을 위해, tbot 클라이언트는 Auth Service에 직접 연결하도록 구성된 경우에도 일반적으로 Proxy Service에 대한 네트워크 액세스를 받아야 합니다.