X.509 인증서로 커밋 및 태그에 서명하기
X.509은 공개 또는 사설 공개키 기반 기반구조(PKI)에 의해 발급된 공개키 인증서의 표준 형식입니다. 개인용 X.509 인증서는 S/MIME(보안/다목적 인터넷 메일 확장)과 같은 인증 또는 서명 목적으로 사용됩니다. 그러나 Git은 또한 GPG(GnuPG 또는 GNU Privacy Guard)와 유사한 방식으로 X.509 인증서로 커밋 및 태그에 서명하는 것을 지원합니다. 주요 차이점은 GitLab이 개발자의 서명이 신뢰할 수 있는지 여부를 결정하는 방식입니다:
- X.509의 경우 루트 인증 기관이 GitLab 신뢰 저장소에 추가됩니다. (신뢰 저장소는 신뢰할 수 있는 보안 인증서의 저장소입니다.) 서명에 필요한 중간 인증서와 결합된 개발자 인증서는 신뢰할 수 있는 루트 인증서로 연결될 수 있습니다.
- GPG의 경우, 개발자들이 자신의 GPG 키를 자신의 계정에 추가합니다.
GitLab은 자체 인증서 저장소를 사용하며, 따라서 신뢰 체인을 정의합니다. GitLab에서 검증을 하려면 커밋이나 태그:
- 서명 인증서 이메일은 GitLab에서 확인된 이메일 주소와 일치해야 합니다.
- GitLab 인스턴스가 서명에 있는 인증서에서 신뢰할 수 있는 인증서 저장소에 이르는 완전한 신뢰 체인을 설정해야 합니다. 이 신뢰 체인에는 서명에서 제공된 중간 인증서가 포함될 수 있습니다. 귀하가 GitLab 인증서 저장소에 인증서를 추가해야 하는 경우도 있습니다.
- 서명 시간은 보통 최대 3년까지 활성화되는 인증서 유효 기간 내에 있어야 합니다.
- 서명 시간은 커밋 시간과 동일하거나 그 이후여야 합니다.
커밋의 상태가 이미 결정되어 데이터베이스에 저장되어 있는 경우, Rake 작업을 사용하여 상태를 다시 확인하세요. Troubleshooting 섹션을 참조하세요. GitLab은 백그라운드 워커를 사용하여 매일 인증서 폐기 목록을 확인합니다.
알려진 이슈
-
authorityKeyIdentifier
,subjectKeyIdentifier
및crlDistributionPoints
가 없는 인증서는 Unverified로 표시됩니다. 이러한 경우 RFC 5280과 일치하는 PKI에서 인증서를 사용하는 것을 권장합니다. - GitLab.com 오퍼링에서는 Verified 배지가 표시되지 않습니다. 왜냐하면 사용자 지정 인증 기관 (CA)를 업로드할 수 있는 기능이 자체 관리형 인스턴스에서만 사용할 수 있기 때문입니다.
- 필수 Key Usage(KU) 외에 인증서의 확장 키 사용(EKU) 부분에 값을 설정하면 커밋이 Unverified로 표시될 가능성이 있습니다.
이 문제를 해결하려면 EKU 목록에
emailProtection
을 추가하세요. 이러한 제한은 RFC 5280에서 지정됩니다. 이를 진단하려면 OpenSSL을 사용한 S/MIME 검증을 따르세요. 이 변경으로 문제를 해결할 수 없는 경우, 이슈 440189에 의견을 제공하세요. - GitLab 16.2 이전 버전에서 서명 인증서의 대체 이메일이 Subject Alternative Name 목록에 두 개 이상 있으면, 커밋을 확인할 때 첫 번째 이메일만 사용됩니다.
- GitLab 15.1 이전 버전에서 발급 기관 인증서의
X509v3 Subject Key Identifier
(SKI) 및 서명 인증서의 SKI는 40자여야합니다. SKI가 더 짧으면 GitLab에서 커밋이 확인되지 않고 짧은 주제 키 식별자는 또한 프로젝트에 액세스할 때 오류를 일으킬 수 있습니다. ‘커밋 서명로드 도중 오류 발생’ 및HTTP 422 Unprocessable Entity
오류와 같은 오류가 발생할 수 있습니다.
서명된 커밋을 위한 설정
커밋, 태그 또는 둘 다에 서명하려면 다음을 수행해야 합니다:
X.509 키 쌍 획득
귀하의 조직이 공개키 기반 구조(PKI)를 보유하고 있다면 그 PKI에서 S/MIME 키를 제공합니다. PKI에서 S/MIME 키 쌍을 제공받지 않은 경우 자체 서명한 쌍을 생성하거나 쌍을 구입할 수 있습니다.
X.509 인증서 Git으로 연결
X.509 서명의 이점을 살리려면 Git 버전이 2.19.0 이상이어야 합니다. Git 버전을 git --version
명령어로 확인할 수 있습니다.
올바른 버전이 있다면 Git을 구성할 수 있습니다.
Linux
서명에 사용할 키를 Git이 사용하도록 구성하세요:
signingkey=$( gpgsm --list-secret-keys | egrep '(key usage|ID)' | grep -B 1 digitalSignature | awk '/ID/ {print $2}' )
git config --global user.signingkey $signingkey
git config --global gpg.format x509
Windows 및 macOS
Windows 또는 macOS를 구성하려면:
-
S/MIME Sign을 설치하세요.
- 설치 프로그램을 다운로드하거나.
- macOS에서
brew install smimesign
을 실행하세요.
- 인증서 ID를 실행하여 가져옵니다
smimesign --list-keys
. - 서명 키를 설정하세요
git config --global user.signingkey <ID>
,<ID>
를 인증서 ID로 대체하세요. -
다음 명령어로 X.509를 구성하세요:
git config --global gpg.x509.program smimesign git config --global gpg.format x509
커밋 서명 및 확인
X.509 인증서를 Git과 연결한 후에 커밋에 서명할 수 있습니다:
- Git 커밋을 생성할 때
-S
플래그를 추가하세요:
git commit -S -m "feat: x509 signed commits"
- GitLab에 푸시한 뒤,
--show-signature
플래그로 커밋이 확인되었는지 확인하세요:
git log --show-signature
-
매번 커밋할 때
-S
플래그를 입력하지 않으려면, 다음 명령을 실행하여 Git에서 매번 커밋할 때 서명하도록 설정하세요:
git config --global commit.gpgsign true
태그 서명 및 확인
X.509 인증서를 Git과 연결한 후에 태그에 서명할 수 있습니다:
- Git 태그를 생성할 때
-s
플래그를 추가하세요:
git tag -s v1.1.1 -m "My signed tag"
- GitLab에 푸시한 후, 다음 명령으로 태그가 서명되었는지 확인하세요:
git tag --verify v1.1.1
-
매번 태그할 때
-s
플래그를 입력하지 않으려면, 다음 명령을 실행하여 Git에서 매번 태그할 때 서명하도록 설정하세요:
git config --global tag.gpgsign true
관련 주제
문제 해결
관리자 액세스 권한이 없는 커미터의 경우, 가능한 해결책을 확인하려면 서명된 커밋의 확인 문제 목록을 검토하세요. 이 페이지의 다른 문제 해결 제안에는 관리자 액세스 권한이 필요합니다.
커밋 재확인
GitLab은 데이터베이스에 확인된 커밋의 상태를 저장합니다. 이전에 확인된 커밋의 상태를 확인하기 위해 Rake 작업을 사용할 수 있습니다.
수정 사항이 있는 경우, 다음 명령을 실행하세요:
sudo gitlab-rake gitlab:x509:update_signatures
주요 확인 사항
코드는 다음의 주요 확인을 수행합니다.
해당 키 확인하며, 모두 verified
를 반환해야 합니다:
-
x509_certificate.nil?
은 false여야 합니다. -
x509_certificate.revoked?
은 false여야 합니다. -
verified_signature
은 true여야 합니다. -
user.nil?
은 false여야 합니다. -
user.verified_emails.include?(@email)
은 true여야 합니다. -
certificate_email == @email
은 true여야 합니다.
커밋이 확인되지 않음
으로 표시되는 이유를 조사하려면:
- Rails 콘솔을 시작합니다:
sudo gitlab-rails console
- 조사 중인 프로젝트(경로 또는 ID로 식별) 및 전체 커밋 SHA를 식별합니다.
이 정보를 사용하여
재미
를 만들어 다른 확인을 실행합니다:
project = Project.find_by_full_path('group/subgroup/project')
project = Project.find_by_id('121')
commit = project.repository.commit_by(oid: '87fdbd0f9382781442053b0b76da729344e37653')
signedcommit=Gitlab::X509::Commit.new(commit)
signature=Gitlab::X509::Signature.new(signedcommit.signature_text, signedcommit.signed_text, commit.committer_email, commit.created_at)
확인 과정에서 확인할 문제를 해결하려면, Rails 콘솔을 종료하고 처음부터 확인을 다시 진행하세요.
- 커밋의 인증서를 확인합니다:
signature.x509_certificate.nil?
signature.x509_certificate.revoked?
두 확인이 false
을 반환해야 합니다:
> signature.x509_certificate.nil?
=> false
> signature.x509_certificate.revoked?
=> false
알려진 문제로 인해
이러한 확인이 Validation failed: Subject key identifier is invalid
로 실패하는 경우가 있습니다.
- 서명에 대한 암호학적 확인을 실행합니다. 코드는
true
을 반환해야 합니다:
signature.verified_signature
false
을 반환하면 이 확인을 더 조사하세요.
- 커밋과 서명의 이메일 주소가 일치하는지 확인합니다:
- Rails 콘솔에서 비교되는 이메일 주소를 확인합니다.
- 마지막 명령은
true
을 반환해야 합니다:
sigemail=signature.__send__:certificate_email
commitemail=commit.committer_email
sigemail == commitemail
GitLab 16.2 및 이전 버전에서는 Subject Alternative Name
목록에서 첫 번째 이메일 주소만 비교됩니다. Subject Alternative Name
목록을 표시하려면 다음을 실행하세요:
signature.__send__ :get_certificate_extension,'subjectAltName'
개발자의 이메일 주소가 목록에서 처음이 아닌 경우,
이 확인이 실패하여 커밋이 확인되지 않음
으로 표시됩니다.
- 커밋의 이메일 주소가 GitLab의 계정과 연결되어 있는지 확인합니다.
이 확인은
false
을 반환해야 합니다:
signature.user.nil?
- GitLab에서 사용자에게 이메일 주소가 연결되어 있는지 확인합니다. 이 확인은
사용자(
#<User id:1234 @user_handle>
)를 반환해야 합니다:
User.find_by_any_email(commit.committer_email)
nil
을 반환하면, 이메일 주소가 사용자에게 연결되지 않고 확인이 실패합니다.
- 개발자의 이메일 주소가 확인되어 있는지 확인합니다. 이 확인은
true
을 반환해야 합니다:
signature.user.verified_emails.include?(commit.committer_email)
이전 확인이 nil
을 반환하면, 다음 명령은 오류를 표시합니다:
NoMethodError (undefined method `verified_emails' for nil:NilClass)
- 확인 상태가 데이터베이스에 저장됩니다. 데이터베이스 레코드를 표시하려면:
pp CommitSignatures::X509CommitSignature.by_commit_sha(commit.sha);nil
이전의 모든 확인이 올바른 값을 반환하면:
-
verification_status: "unverified"
는 데이터베이스 레코드를 업데이트해야 함을 나타냅니다. Rake 작업을 사용하여 업데이트하십시오. -
[]
는 데이터베이스에 레코드가 아직 없음을 나타냅니다. 서명을 확인하고 결과를 저장하려면 커밋을 GitLab에서 찾으십시오.
암호 검증 확인
만약 GitLab이 verified_signature
가 false
임을 결정한다면, 레일즈 콘솔에서 해당 이유를 조사하십시오. 이러한 확인 작업은 signature
가 존재하는 것을 요구합니다. 이전 주요 검증 확인의 signature
단계를 참조하십시오.
-
확인 작업을 거쳐, 발급자를 확인하지 않고 서명만 확인합니다. 결과는
true
여야 합니다.signature.__send__ :valid_signature?
-
서명 시간과 날짜를 확인합니다. 이 확인 작업은
true
를 반환해야 합니다.signature.__send__ :valid_signing_time?
- 이 코드에서는 코드 서명 인증서가 만료될 수 있습니다.
-
커밋은 인증서의 유효 기간 동안에 서명돼야 하며, 커밋의 날짜스탬프 시간 이후여야 합니다. 커밋 시간과
not_before
,not_after
를 포함한 인증서 세부정보를 표시합니다:commit.created_at pp signature.__send__ :cert; nil
-
TLS 신뢰를 설정할 수 있는 서명 확인 작업을 포함한 서명을 확인합니다. 결과는
true
여야 합니다.signature.__send__(:p7).verify([], signature.__send__(:cert_store), signature.__send__(:signed_text))
-
이 작업이 실패하면, 신뢰를 설정하기 위해 필요한 누락된 인증서를 GitLab 인증서 저장소에 추가하십시오.
-
더 많은 인증서를 추가한 후, (문제 해결 절차를 통해 성공한다면) 커밋을 재검증하기 위해 Rake 작업을 실행합니다.
-
문제 해결을 위해 레일즈 콘솔에서 동적으로 추가적인 인증서를 추가할 수 있습니다.
-
변경 가능한 신뢰 저장소
cert_store
로 서명을 재검증합니다. 여전히false
일 것입니다.cert_store = signature.__send__ :cert_store signature.__send__(:p7).verify([], cert_store, signature.__send__(:signed_text))
-
추가적인 인증서를 추가한 후 재검증합니다:
cert_store.add_file("/etc/ssl/certs/my_new_root_ca.pem") signature.__send__(:p7).verify([], cert_store, signature.__send__(:signed_text))
-
-
서명에 포함된 인증서를 표시합니다:
pp signature.__send__(:p7).certificates ; nil
-
추가 중간 인증서 및 루트 인증서를 인증서 저장소에 추가하십시오. 웹 서버에서 인증서 체인이 구축되는 방식과 일관성을 유지하도록합니다:
- 커밋을 서명하는 Git 클라이언트는 서명에 루트 및 모든 중간 인증서를 포함해야 합니다.
- GitLab 인증서 저장소에는 루트만 포함해야합니다.
GitLab에서 루트 인증서를 인증서 저장소에서 제거하면(만료될 때와 같이), 해당 루트로 연결된 커밋 서명은 unverified
로 표시됩니다.
OpenSSL을 사용한 S/MIME 검증
서명에 문제가 있거나 TLS 신뢰에 실패하는 경우, OpenSSL을 사용하여 명령 줄에서 추가 디버깅을 수행할 수 있습니다.
Rails 콘솔에서 서명 및 서명된 텍스트를 내보내십시오:
-
주요 검증 확인의 초기 두 단계를 거친 후
signature
가 설정된 상태여야 합니다. -
OpenSSL 요구사항에 따라, PKCS7 PEM 형식의 데이터는 일반적으로
BEGIN PKCS7
및END PKCS7
로 구성돼야 합니다.pkcs7_text = signature.signature_text.sub('-----BEGIN SIGNED MESSAGE-----', '-----BEGIN PKCS7-----') pkcs7_text = pkcs7_text.sub('-----END SIGNED MESSAGE-----', '-----END PKCS7-----')
-
서명 및 서명된 텍스트를 작성합니다:
f1=File.new('/tmp/signature_text.pk7.pem','w') f1 << pkcs7_text f1.close f2=File.new('/tmp/signed_text.txt','w') f2 << signature.signed_text f2.close
이 데이터를 Linux 명령 줄에서 OpenSSL을 사용하여 조사할 수 있습니다:
-
서명이 포함된 PKCS #7 파일을 조회할 수 있습니다:
/opt/gitlab/embedded/bin/openssl pkcs7 -inform pem -print_certs \ -in /tmp/signature_text.pk7.pem -print -noout
출력에서 최소한 하나의
cert
섹션을 포함해야 합니다. 서명자의 인증서입니다.출력에는 상세한 수준의 많은 세부 정보가 있습니다. 여기에는 일부 구조와 제목의 예시가 포함됩니다.
PKCS7: d.sign: cert: cert_info: issuer: validity: notBefore: notAfter: subject:
개발자의 코드 서명 인증서가 중간 인증 기관에 의해 발급되었다면, 추가적인 인증서 세부 정보가 있어야 합니다.
PKCS7: d.sign: cert: cert_info: cert: cert_info:
-
서명에서 인증서를 추출할 수 있습니다:
/opt/gitlab/embedded/bin/openssl pkcs7 -inform pem -print_certs \ -in /tmp/signature_text.pk7.pem -out /tmp/signature_cert.pem
이 단계가 실패하는 경우, 서명자의 인증서가 없을 수 있습니다.
- Git 클라이언트에서 이 문제를 해결하십시오.
- 다음 단계는 실패하지만, 서명자의 인증서를 GitLab 서버로 복사하면,
-nointern -certfile signerscertificate.pem
를 사용하여 테스트를 수행할 수 있습니다.
-
추출한 인증서를 사용하여 커밋을 부분적으로 검증합니다:
/opt/gitlab/embedded/bin/openssl smime -verify -binary -inform pem \ -in /tmp/signature_text.pk7.pem -content /tmp/signed_text.txt \ -noverify -certfile /tmp/signature_cert.pem -nointern
일반적으로 출력에는 다음이 포함됩니다:
- 상위 커밋
- 커밋에서의 이름, 이메일, 타임스탬프
- 커밋 텍스트
-
Verification successful
등과 유사한 내용
이 확인 작업은 GitLab에서 수행되는 확인 작업과 동일하지 않습니다.
- 서명자의 인증서를 확인하지 않습니다 (
-noverify
) - 검증은 메시지 내의
-certfile
대신 사용된-cert
을 사용하여 수행됩니다 (-nointern
)
-
메시지 내의 인증서를 사용하여 커밋을 부분적으로 검증합니다:
/opt/gitlab/embedded/bin/openssl smime -verify -binary -inform pem \ -in /tmp/signature_text.pk7.pem -content /tmp/signed_text.txt \ -noverify
추출한 인증서를 사용한 이전 단계와 동일한 결과를 가져와야 합니다.
메시지가 인증서가 없는 경우, 오류에는
signer certificate not found
가 포함됩니다. -
커밋을 완전히 확인합니다:
/opt/gitlab/embedded/bin/openssl smime -verify -binary -inform pem \ -in /tmp/signature_text.pk7.pem -content /tmp/signed_text.txt
이 단계가 실패하는 경우, GitLab에서도 검증이 실패합니다.
오류를 해결하십시오. 예를 들어:
-
certificate verify error .. unable to get local issuer certificate
:- 신뢰 체인을 설정할 수 없습니다.
- 이 OpenSSL 바이너리는 GitLab 신뢰 저장소를 사용합니다. 신뢰 저장소에서 루트 인증서가 누락되었거나, 서명에 중간 인증서가 누락되어 신뢰할 수 있는 루트로의 체인을 만들지 못했습니다.
- 서명에 포함할 수 없는 경우 중간 인증서를 신뢰 저장소에 추가할 수 있습니다.
-
신뢰할 수 있는 인증서를 추가하는 절차 -
/etc/gitlab/trusted-certs
를 사용하여 패키지화된 GitLab에 대한 신뢰 저장소에.
- OpenSSL로 추가 신뢰할 수 있는 인증서를 테스트합니다:
-CAfile /path/to/rootcertificate.pem
-
unsupported certificate purpose
: -
signer certificate not found
, 다음 중 하나:-
-nointern
인수는 추가했지만-certfile
을 제공하지 않은 경우입니다. - 서명자의 인증서가 포함되지 않은 경우입니다.
-
-