Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
ongoing |
@igor.drozdov
|
@stanhu
| devops create | 2023-07-28 |
SSH証明書
要約
GitLab.comでは、顧客は自分の最上位グループ(後の組織)を取得します。自己管理に比べて、このレベルで組織全体の設定を管理する必要があります。
現在、SaaSで提供されているGitアクセスコントロールオプション(SSH、HTTPS)は、ユーザープロファイルで設定されたクレデンシャル(アクセストークン、SSHキー)に依存しています。ユーザープロファイルは組織のコントロール外にあるため、その鍵が秘密に保たれているかどうか、有効期限がポリシーに合っているかどうかを顧客が評価する方法はありません。また、Gitへのアクセス・フローにMFAを適用することもできないため、万が一鍵が流出した場合のダメージ・コントロールもほとんどできません。
顧客は、開発者が日常的に MFA を使って一時的な SSH 証明書を要求し、内部システムにアクセスできるようにするプロセスを用意しているかもしれません。SaaSで同じように作業できるようにするには、Gitアクセス制御の目的で、公開認証局(CA
)ファイルをGitLab.com SaaSと共有する方法が必要です。
動機
- GitLab.com SaaSで公開認証局(
CA
)ファイルをユーザーと共有できるようにし、Gitのアクセス制御を実現。 - GitLabと、SSH証明書による認証をすでにサポートしている競合製品との間の製品ギャップを埋めます。
目標
本文書では、以下の要件を満たす機能を実装するためのアーキテクチャ設計を提案します:
- 証明書の発行に使用する
CA
ファイル (CA.pub
) の公開鍵をグループに追加できること。 -
CA
で発行された証明書を使うと、グループやその祖先のプロジェクトに Git でアクセスできるようになります。 - この証明書は、そのグループとその祖先以外のプロジェクトへの Git アクセスには使えません。
非目標
このドキュメントでは、SSH 証明書による認証をサポートするための Core 機能を提供することに焦点を当てています。潜在的な改善点についてはFollow Ups に記述されています。
提案
車々間通信
グループ管理者は、認証局ファイル (ssh-keygen -f CA
) として使用する SSH キーペアを生成します:
- 秘密鍵はユーザー証明書のイシューに使用されます。
- 公開鍵は、ユーザー証明書を介してグループにアクセスを許可するために、グループに追加されます。
ユーザー証明書
グループ管理者はCA
秘密鍵を使ってユーザー証明書をイシューし、GitLab ユーザー名かユーザーのプライマリーメールを鍵のアイデンティティとして指定します:
ssh-keygen -s CA -I user@example.com -V +1d user-key.pub
その結果、以下のような構造のユーザー証明書が生成されます:
ssh-keygen -L -f ssh_host_ed25519_key-cert.pub
ssh_host_ed25519_key-cert.pub:
Type: ssh-ed25519-cert-v01@openssh.com user certificate
Public key: ED25519-CERT SHA256:dRVV49XJHt85X1seqr9xXyxyuuGTbtFV6Lbwlrx6BIQ
Signing CA: RSA SHA256:UAcgUeGoXrs8WOT/N+bmqY2vB9145Mc5NaN1Y977NCI (using rsa-sha2-512)
Key ID: "user@example.com"
Serial: 1
Valid: from 2023-07-31T18:20:00 to 2023-08-01T18:21:34
Principals: (none)
Critical Options: (none)
Extensions:
permit-X11-forwarding
permit-agent-forwarding
permit-port-forwarding
permit-pty
permit-user-rc
-
Type
はユーザー証明書のタイプです。GitLab Shellが受け入れるのはユーザー証明書のみで、他のタイプはすべて拒否されます。 -
Public Key
はユーザーの公開鍵です。 -
Signing CA
は、CA
の公開鍵です。そのフィンガープリントは、ユーザー証明書に関連付けられているグループを見つけるために使用されます。 -
Key ID
はユーザーのユーザー名かプライマリメールです。GitLabユーザーをユーザー証明書に関連付けるために使用されます。 -
Serial
はユーザー証明書のシリアル番号です。同じCA
によって作成された異なる証明書を区別するために使用できます。 -
Valid
は有効期間を示します。この値はGitLab Shellによって検証されます:期限切れでまだ有効でないユーザー証明書は拒否されます。 -
Principals
Critical Options
とExtensions
はユーザー証明書に追加情報を埋め込むために使用されます。このフィールドは将来、ユーザー証明書に追加の制限を適用するために使用される可能性があります。
アプリケーションの動作
GitLab Shellは、SSH経由でGitLabインスタンスに送られるコマンドの処理を担当するプロジェクトです。ユーザがSSH接続を確立し公開キーで認証しようとすると、GitLab Shellは/authorized_keys
エンドポイントに内部APIリクエストを送り、そのキーがGitLabユーザに関連付けられているかどうかを検出します。認証に証明書が使われている場合、GitLab Shellはそれを認識し、代わりに/authorized_certs
へのリクエストを実行することができます。
- グループ管理者が
CA.pub
ファイルをグループに追加します。 - ユーザーが
CA
で署名された証明書を使用して認証を試みます。 - GitLab Shell は
CA
のフィンガープリントとユーザー ID(GitLab のユーザー名かプライマリメール)を/authorized_certs
に送信します。 - GitLab Railsはフィ
CA.pub
ンガープリントが追加さCA.pub
れたCA.pub
グループとユーザーをCA.pub
見つけます。CA
とグループの間の一対一の関係を定義するフィンガープリントによってCA.pub
、CA.pub
インスタンスで一意になります。 - GitLab Shell は確立された接続の名前空間フルパスを記憶します。
- GitLab Shell は
/allowed
ユーザーが特定のプロジェクトにアクセスできるかどうかのチェックが必要になるたびにエンドポイントに/allowed
リクエストを送ります。/allowed
名前空間フルパスは/allowed
エンド/allowed
ポイントに渡さ/allowed
れます。 - GitLab Railsは、ユーザーが証明書経由でこのプロジェクトにアクセスできるかどうかを判断するために、名前空間がプロジェクトの名前空間またはその祖先の一つと一致するかどうかをチェックします。
- 上記のチェックがすべて成功すると、ユーザーはプロジェクトにアクセスできるようになります。
使用例
-
CA.pub
を設定するグループ外のプロジェクトにアクセスします。次のようなグループの階層があるとします。
a/b/c/d/e/f | └/g/h/i
- グループ管理者は
CA.pub
をd
に追加し、ユーザはCA
によって署名された証明書を使用して認証されます。 - ユーザーが
a/b/c/d/e/f/project
をクローンすると、a/b/c/d/e/project
プロジェクトのフルパスとa/b/c/d
名前空間のフルパスを送信します。d
はプロジェクトの名前空間の祖先であるため、ユーザーはプロジェクトのクローンを許可されます。 - ユーザーが
a/b/c/g/h/i/project
をクローンする場合、d
が祖先のリストにないため、ユーザーはプロジェクトのクローンを許可されません。
- グループ管理者は
-
CA.pub
を設定するグループは、別のネームスペースに転送されます。
ネームスペースのフル・パスは接続ごとに保存されるため、既存の証明書はまだ有効です。ユーザーが再接続すると、/authorized_certs
に別の要求が送信され、ネームスペースの新しいフル・パスが返されます。
オープンな質問
異なるプロジェクトへの複数のSSH証明書
ユーザーは異なるプロジェクトにアクセスするために異なる SSH 証明書を持っているかもしれません。ユーザーが SSH 接続を確立するとき、SSH クライアントは認証に成功するものを見つけるために、いくつかの候補を繰り返します。現在のアーキテクチャでは、ユーザーが別のプロジェクトにアクセスするためであっても、名前空間へのアクセスを提供する最初の証明書が受け入れられます。
使用例:
- ユーザーは、
a
およびb
グループに対して有効な証明書を持っています。 - ユーザは、
a
を使用して正常に認証されます。 - ユーザーは
b/project
をクローンしようとして失敗します。
このシナリオの回避策は、SSH接続時に特定の証明書を使うようにGitを設定することです。.gitconfig
ファイルに以下を追加します:
[core]
sshCommand = ssh git@gitlab.com -i cert.pub
単一の証明書を無効にすることはできません
単一のユーザー証明書の失効は、この MVC の範囲外です。この機能を実装することは可能ですが、実現可能性については議論する必要があります。
この機能をサポートすると、実装とUI/UXが複雑になります。しかし、危殆化した証明書のリスクは、以下のアクションによって大幅に減らすことができます:
- ユーザー証明書の有効期限。ドキュメントで強く推奨すべきです。
- 現在のユーザー証明書をすべて失効させるCAのローテーション。
- ユーザー証明書を使用できる IP アドレスを制限できる
source-address
機能の実装。
証明書は複数のGitLabインスタンスで使用することができます。
GitLabインスタンスに関する情報はユーザー証明書には埋め込まれません。つまり、KeyId
の値がそれらのインスタンスで認識される限り、複数の GitLab インスタンスにまたがって使用することができます。
解決策
- ユーザー証明書の使用を特定のインスタンスに制限するオプション・フィールドは、フォローアップで
Extensions
を使用して実装できます。extension:login@gitlab.com=username
を指定する方がよりセキュアで柔軟なオプションですが、両方に対応できます。
CA を複数のグループで再利用することはできません。
CA.pub
フィンガープリントは一意でなければならず、複数のグループで再利用することはできません。一対一の関係は、ユーザーがアクセスできる一つのグループを見つけることができるように設計によって選ばれています。
もう一つの選択肢は、Extensions
またはCritical Options
を使用してユーザー証明書に名前空間を埋め込むことです。
長所
-
CA
複数のグループで再利用できます。 - ユーザー証明書は、どのグループにアクセスできるかを_尋ねる_のではなく、どのグループにアクセスできるかを_指示_します。
短所
- ユーザー証明書フォーマットのカスタム要件が必要。
- 他のグループが
CA.pub
を追加した場合、ユーザーは意図せずにそのグループへのアクセスを取得する可能性があります。
解決策
- ユーザー証明書の使用を特定のグループに制限するオプション・フィールドは、フォローアップの
Extensions
またはCritical Options
を使用して実装できます。CA
は依然として再利用できませんが、ユーザー証明書を他のグループに使用することはできません。
反復計画
コンポーネント | Milestone | グループ | 変更点 |
---|---|---|---|
GitLab シェル | 16.3 | ソースコード | GitLab ShellにSSH証明書を使った認証を実装する方法 |
GitLab Rails | 16.4 | ソースコード | GitLab Rails API の内部エンドポイントauthorized_certs を実装して、設定するグループを探します。CA.pub
|
GitLab Rails | 16.4 | ソースコード | グループのための GitLab Rails API エンドポイントを実装します。CA.pub
|
GitLab Rails | Next 2-3 milestones | 認証と作成者許可 | 追加/削除のためのグループ設定UXの実装CA.pub
|
GitLab Rails | Next 2-3 milestones | 認証と作成者許可 | 認証にSSH証明書のみを使用し、個人のSSHキーとアクセストークンを禁止するオプションを実装します。 |
フォローアップ
トピックに関連する機能ですが、このブループリントの範囲外です:
- インスタンスやグループで Git over HTTPS を無効にすることで、認証に SSH 証明書だけを使うようにします。
- インスタンスやグループでの個人SSHキーの使用を禁止することで、グループレベルのSSHキーのみを使うようにします。
- ユーザー証明書の使用をIPアドレスのセットに制限する
source-address
Critical Option
。 - ユーザー証明書の利用をインスタンスのセットに制限する
login@hostname=username
Extensions
の指定:ありがたい機能。 - SSH証明書を使ったコミットへの署名: あると便利な機能。
- 単一のユーザー証明書の失効。複雑なUI/UXが必要ですが、他の機能を使うことでリスクを大幅に軽減できます。