Infograb logo
머신 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 )에서만 콘텐츠를 복사하거나 공유하십시오.

기본 원인을 해결한 후, 잠긴 봇을 재설정하기 위해 다음 단계를 따르십시오:

  1. 봇 사용자에 대한 잠금을 제거합니다.
  2. 새 봇 인스턴스를 생성하여 봇의 생성 카운터를 재설정합니다.

먼저 봇 사용자에 대한 잠금을 찾아서 제거합니다. 이 예에서는 봇의 이름이 example 이라고 가정하며, 이에 따라 bot-example 이라는 Teleport 사용자와 연결됩니다:

tctl get locks
kind: 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: 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]      봇 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.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 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 ls
Name 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.yamlroles: ... 매개변수를 사용하여 이러한 역할의 하위 집합만 부여할 수 있습니다.

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

문제가 해결된 후, 업데이트된 역할이 적용되도록 tbot 클라이언트를 재시작하거나 다시 로드하십시오.

봇이 처음에 역할을 부여받지 못한 경우, 가장 간단한 해결 방법은 봇을 삭제하고 재생성하는 것입니다. 이때 --roles=... 플래그에 역할을 포함시켜야 합니다:

tctl bots rm example
tctl 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 라우팅/다중화가 활성화된 경우에만 올바르게 작동합니다.

Teleport 원문 보기