最近、個人的にsigstoreのKeyless Signingがアツいです。以下のブログを読みました。
これらの記事は主にコンテナイメージの署名について解説しているのですが、sigstoreはバイナリの署名にも使えます。以前から、複数メンテナ体制で秘密鍵をどう共有しよう?とか、公開鍵の安全な配布方法って無くない?と考えていたので、渡りに船です。
チームでひとつの鍵を保守したい場合とかどうやってるんだろ、みんなに主キー配るんかな、まぁそりゃそうか...
— wata (@wata727_) 2021年5月1日
リリースバイナリの署名に使った鍵をキーサーバーで公開してたら、今それ信用できんのでリポジトリに公開鍵入れてくれという話が来ていた、もう何も信用できないhttps://t.co/2g5diZxGIM
— wata (@wata727_) 2019年12月24日
早速、採用に向けて色々調べていたのですが、署名した人をどう確認しているのか、改ざんされていないことをどう保証しているのかがわからなかったので、Keyless Signingでは何を検証する必要があるのかを調べました。
全然わからない状態から調べているので、間違ったことを書いてるかもしれません。何か間違いを見つけたらTwitterとかで教えて下さい。
CosignによるKeyless Signing
実際に動かしながら確認したいので、まずは署名と検証を試してみます。CosignというCLIを使います。
この記事を書いている時点の最新版であるv1.7.2では、Keyless Signingは実験的機能であり、環境変数COSIGN_EXPERIMENTAL=1
を設定する必要があります。署名する対象は適当なUUIDのテキストファイルです。
$ uuidgen > artifact.txt $ cat artifact.txt D4A671E9-BC95-47B9-840B-D92517348960 $ COSIGN_EXPERIMENTAL=1 cosign sign-blob --output-signature artifact.txt.sig artifact.txt Using payload from: artifact.txt Generating ephemeral keys... Retrieving signed certificate... Your browser will now be opened to: https://oauth2.sigstore.dev/auth/auth?access_type=online&client_id=sigstore&code_challenge=... Successfully verified SCT... using ephemeral certificate: -----BEGIN CERTIFICATE----- MIICEDCCAZegAwIBAgITE9tB5vLrfUDhWfcvIlAoPmURGjAKBggqhkjOPQQDAzAq MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIy MDQyMzEzMjEwM1oXDTIyMDQyMzEzMzEwMlowADBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABJwVpj2x/WjymidiXnY0H0ONkFQApzd/DmxnaHVpxqQYWlfLCr4L6n9g musqV8t4SMvIgh5us/x62RU6iNrr1YOjgcUwgcIwDgYDVR0PAQH/BAQDAgeAMBMG A1UdJQQMMAoGCCsGAQUFBwMDMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFB2/WTE9 LwhxEvPFeXMJT6afTHl3MB8GA1UdIwQYMBaAFFjAHl+RRaVmqXrMkKGTItAqxcX6 MCIGA1UdEQEB/wQYMBaBFHdhdGFzc2Jhc3NAZ21haWwuY29tMCkGCisGAQQBg78w AQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTAKBggqhkjOPQQDAwNnADBk AjAPme8wCmrTiWFBChw7km5hMSpkgtbEP6m86iyjOQty6xdOB/tScXsJ3hcQ8f2r zrECMAjn4c/7uByMdtXGN7TLhlw7suMhuRlbCqP/rXj3Zdwx+x+393WJPqridQfI b6Xjcw== -----END CERTIFICATE----- tlog entry created with index: 2093484 Signature wrote in the file artifact.txt.sig
cosign sign-blob
を実行すると、ブラウザが立ち上がり、GitHub、Google、Microsoftアカウントのいずれかでログインが求められます。ログインに成功すると、手元にartifact.txt.sig
ファイルが保存されます。
検証はcosign verify-blob
で行います。
$ COSIGN_EXPERIMENTAL=1 cosign verify-blob --signature artifact.txt.sig artifact.txt tlog entry verified with uuid: 94d9cb793c8e7439f300755070fb04af35b821191f0ab3a70e0c6f3dd84dbc47 index: 2093484 Verified OK
別のファイルに対して検証するとちゃんと失敗します。
$ COSIGN_EXPERIMENTAL=1 cosign verify-blob --signature artifact.txt.sig artifact_malformed.txt Error: verifying blob [artifact_malformed.txt]: could not find a tlog entry for provided blob main.go:46: error during command execution: verifying blob [artifact_malformed.txt]: could not find a tlog entry for provided blob
ここまで、署名側、検証側のどちらも秘密鍵、公開鍵を意識しませんでした。なぜ正規のファイルの検証だけを成功させることができるのでしょうか?
攻撃側から考える検証
今回のartifact.txt
に対する検証を攻撃側から考えてみます。
攻撃1: ファイルの差し替え
まず、artifact.txt
を検証なしで受け入れる場合、どのような攻撃ができるでしょうか?
単純にartifact.txt
を悪意のあるファイルに差し替えることできます。GitHubのリリースに添付されているバイナリであれば、メンテナのアクセストークンを手に入れられれば、簡単にファイルを差し替えられます。
アクセストークンを手に入れることは、残念ながらそれほど難しいことではありません。GitHub連携したサービスからの流出や、GitHub Actionsでのコマンドインジェクションなど、実例は多くあります。
これを防ぐためには、artifact.txt
が正規のファイルであることを検証できる必要があります。メンテナは秘密鍵と公開鍵を生成し、秘密鍵でartifact.txt
を署名し、それをシグネチャファイルartifact.txt.sig
として公開します。利用者は公開鍵を使って、artifact.txt.sig
を検証することで、正規のファイルであることを確認します。
この署名があれば、攻撃者はメンテナの秘密鍵を手を入れない限り、差し替えたartifact_malformed.txt
に対応するシグネチャファイルを生成できないため、攻撃は失敗します。
CosignではVerifySignature
でシグネチャを検証しています。
// verify the signature if err := verifier.VerifySignature(bytes.NewReader([]byte(sig)), bytes.NewReader(blobBytes)); err != nil { continue }
https://github.com/sigstore/cosign/blob/v1.7.2/cmd/cosign/cli/verify/verify_blob.go#L214-L217
攻撃2: 公開鍵の差し替え
しかし、ここには重大な問題があります。利用者はどうやって公開鍵を取得すれば良いのでしょうか。artifact.txt
と同じように公開鍵を取得する場合、公開鍵だけ差し替えられていない保証はありません。攻撃者がartifact_malformed.txt
を自身の秘密鍵で署名し、シグネチャファイルと公開鍵を差し替えると、攻撃は成立します。
ここからがKeyless Signingの解説です。CosignはRekorというTransparency Log(以下、Tログ)を提供するサービスから公開鍵を取得します。Tログは署名時に必ず作成されます。
tlogEntry, err := cosign.GetTlogEntry(ctx, rClient, u) if err != nil { continue } certs, err := extractCerts(tlogEntry) if err != nil { continue }
https://github.com/sigstore/cosign/blob/v1.7.2/cmd/cosign/cli/verify/verify_blob.go#L190-L198
Tログには証明書が埋め込まれており、そこから公開鍵を取得できます。rekor-cliを使うと、実際のTログを確認できます。UUIDはartifact.txt
のsha256ハッシュから検索できます。
$ rekor-cli search --artifact artifact.txt Found matching entries (listed by UUID): 94d9cb793c8e7439f300755070fb04af35b821191f0ab3a70e0c6f3dd84dbc47 $ rekor-cli get --uuid 94d9cb793c8e7439f300755070fb04af35b821191f0ab3a70e0c6f3dd84dbc47 LogID: c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d Index: 2093484 IntegratedTime: 2022-04-23T13:21:09Z UUID: 94d9cb793c8e7439f300755070fb04af35b821191f0ab3a70e0c6f3dd84dbc47 Body: { "HashedRekordObj": { "data": { "hash": { "algorithm": "sha256", "value": "3aece84d7d32f68ac07e5d5d4fbba6e16085693e871d31a304ff55048c89e60d" } }, "signature": { "content": "MEQCIE0D6m4Lew8Umdz7vUQsMZwVZpEBIc3Oz6lVKhxbsbeZAiBs2KLR7sWwUxXrIQFVHe4Lfsjtu8naaiL+39GEZLWe8w==", "publicKey": { "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNFRENDQVplZ0F3SUJBZ0lURTl0QjV2THJmVURoV2ZjdklsQW9QbVVSR2pBS0JnZ3Foa2pPUFFRREF6QXEKTVJVd0V3WURWUVFLRXd4emFXZHpkRzl5WlM1a1pYWXhFVEFQQmdOVkJBTVRDSE5wWjNOMGIzSmxNQjRYRFRJeQpNRFF5TXpFek1qRXdNMW9YRFRJeU1EUXlNekV6TXpFd01sb3dBREJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQkp3VnBqMngvV2p5bWlkaVhuWTBIME9Oa0ZRQXB6ZC9EbXhuYUhWcHhxUVlXbGZMQ3I0TDZuOWcKbXVzcVY4dDRTTXZJZ2g1dXMveDYyUlU2aU5ycjFZT2pnY1V3Z2NJd0RnWURWUjBQQVFIL0JBUURBZ2VBTUJNRwpBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TURNQXdHQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZCMi9XVEU5Ckx3aHhFdlBGZVhNSlQ2YWZUSGwzTUI4R0ExVWRJd1FZTUJhQUZGakFIbCtSUmFWbXFYck1rS0dUSXRBcXhjWDYKTUNJR0ExVWRFUUVCL3dRWU1CYUJGSGRoZEdGemMySmhjM05BWjIxaGFXd3VZMjl0TUNrR0Npc0dBUVFCZzc4dwpBUUVFRzJoMGRIQnpPaTh2WVdOamIzVnVkSE11WjI5dloyeGxMbU52YlRBS0JnZ3Foa2pPUFFRREF3Tm5BREJrCkFqQVBtZTh3Q21yVGlXRkJDaHc3a201aE1TcGtndGJFUDZtODZpeWpPUXR5NnhkT0IvdFNjWHNKM2hjUThmMnIKenJFQ01Bam40Yy83dUJ5TWR0WEdON1RMaGx3N3N1TWh1UmxiQ3FQL3JYajNaZHd4K3grMzkzV0pQcXJpZFFmSQpiNlhqY3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" } } } }
publicKey
はBase64エンコードされており、デコードすると証明書が手に入ります。
$ rekor-cli get --uuid 94d9cb793c8e7439f300755070fb04af35b821191f0ab3a70e0c6f3dd84dbc47 --format json | jq -r '.Body.HashedRekordObj.signature.publicKey.content' > publicKey $ cat publicKey | base64 --decode -----BEGIN CERTIFICATE----- MIICEDCCAZegAwIBAgITE9tB5vLrfUDhWfcvIlAoPmURGjAKBggqhkjOPQQDAzAq MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIy MDQyMzEzMjEwM1oXDTIyMDQyMzEzMzEwMlowADBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABJwVpj2x/WjymidiXnY0H0ONkFQApzd/DmxnaHVpxqQYWlfLCr4L6n9g musqV8t4SMvIgh5us/x62RU6iNrr1YOjgcUwgcIwDgYDVR0PAQH/BAQDAgeAMBMG A1UdJQQMMAoGCCsGAQUFBwMDMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFB2/WTE9 LwhxEvPFeXMJT6afTHl3MB8GA1UdIwQYMBaAFFjAHl+RRaVmqXrMkKGTItAqxcX6 MCIGA1UdEQEB/wQYMBaBFHdhdGFzc2Jhc3NAZ21haWwuY29tMCkGCisGAQQBg78w AQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTAKBggqhkjOPQQDAwNnADBk AjAPme8wCmrTiWFBChw7km5hMSpkgtbEP6m86iyjOQty6xdOB/tScXsJ3hcQ8f2r zrECMAjn4c/7uByMdtXGN7TLhlw7suMhuRlbCqP/rXj3Zdwx+x+393WJPqridQfI b6Xjcw== -----END CERTIFICATE-----
ここから公開鍵を抽出します。
cat publicKey | base64 --decode | openssl x509 -pubkey -noout -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnBWmPbH9aPKaJ2JedjQfQ42QVACn N38ObGdodWnGpBhaV8sKvgvqf2Ca6ypXy3hIy8iCHm6z/HrZFTqI2uvVgw== -----END PUBLIC KEY-----
この公開鍵を使い、シグネチャファイルを検証します。しかし、これでは公開鍵が攻撃者によって差し替えられていないことを保証できていません。
もっと言えば、Tログの登録は誰でもできてしまうので、攻撃者は差し替える必要すらありません。上記の手順と同じように、artifact_malformed.txt
でcosign sign-blob
すれば良いのです。
これを防ぐためには、証明書をちゃんと確認する必要があります。opensslで詳しく見てみましょう。
$ cat publicKey | base64 --decode | openssl x509 -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: 13:db:41:e6:f2:eb:7d:40:e1:59:f7:2f:22:50:28:3e:65:11:1a Signature Algorithm: ecdsa-with-SHA384 Issuer: O=sigstore.dev, CN=sigstore Validity Not Before: Apr 23 13:21:03 2022 GMT Not After : Apr 23 13:31:02 2022 GMT Subject: Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: 04:9c:15:a6:3d:b1:fd:68:f2:9a:27:62:5e:76:34: 1f:43:8d:90:54:00:a7:37:7f:0e:6c:67:68:75:69: c6:a4:18:5a:57:cb:0a:be:0b:ea:7f:60:9a:eb:2a: 57:cb:78:48:cb:c8:82:1e:6e:b3:fc:7a:d9:15:3a: 88:da:eb:d5:83 ASN1 OID: prime256v1 NIST CURVE: P-256 X509v3 extensions: X509v3 Key Usage: critical Digital Signature X509v3 Extended Key Usage: Code Signing X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: 1D:BF:59:31:3D:2F:08:71:12:F3:C5:79:73:09:4F:A6:9F:4C:79:77 X509v3 Authority Key Identifier: keyid:58:C0:1E:5F:91:45:A5:66:A9:7A:CC:90:A1:93:22:D0:2A:C5:C5:FA X509v3 Subject Alternative Name: critical email:watassbass@gmail.com 1.3.6.1.4.1.57264.1.1: https://accounts.google.com Signature Algorithm: ecdsa-with-SHA384 30:64:02:30:0f:99:ef:30:0a:6a:d3:89:61:41:0a:1c:3b:92: 6e:61:31:2a:64:82:d6:c4:3f:a9:bc:ea:2c:a3:39:0b:72:eb: 17:4e:07:fb:52:71:7b:09:de:17:10:f1:fd:ab:ce:b1:02:30: 08:e7:e1:cf:fb:b8:1c:8c:76:d5:c6:37:b4:cb:86:5c:3b:b2: e3:21:b9:19:5b:0a:a3:ff:ad:78:f7:65:dc:31:fb:1f:b7:f7: 75:89:3e:aa:e2:75:07:c8:6f:a5:e3:73
注目すべきは、X509v3 extensionsの欄です。ここには署名する際に利用したサービスがGoogleであること、ログインしたアカウントのメールアドレスが記録されています。これによって、署名を行った人物を特定でき、攻撃者が勝手に登録した証明書との区別ができます。
しかし、このX509v3 extensionsは改ざんされていないと言えるでしょうか?これを検証するためには、証明書チェーンを確認する必要があります。X.509証明書は発行元のFulcioというサービスによって署名されており、攻撃者はFulcioの秘密鍵を手に入れない限り、公開鍵はもちろん、X509v3 extensionsの中身を改ざんできません。
opensslを使えば、以下のように検証できます。
$ cat publicKey | base64 --decode | openssl verify -CAfile fulcio_v1.crt.pem stdin: error 10 at 0 depth lookup:certificate has expired OK
証明書の有効期限は10分しか無いため、certificate has expiredエラーが発生します。しかし、後ほど説明しますが、Tログは後から改ざんできないため、証明書が有効な間にTログが登録されたことさえ確認できれば、検証時点で証明書が有効かどうかは重要ではありません。よって無視しても大丈夫です。
この証明書の検証は、cosign.ValidateAndUnpackCert
で行っています。以下は証明書のメールアドレスを検証するコードです。
// Now verify the cert, then the signature. if err := TrustedCert(cert, co.RootCerts, co.IntermediateCerts); err != nil { return nil, err } if co.CertEmail != "" { emailVerified := false for _, em := range cert.EmailAddresses { if co.CertEmail == em { emailVerified = true break } } if !emailVerified { return nil, errors.New("expected email not found in certificate") } }
https://github.com/sigstore/cosign/blob/v1.7.2/pkg/cosign/verify.go#L153-L168
さて、勘の鋭い人はここで「Fulcioの公開鍵はどうやって安全に取得するの?」と思うかもしれません。これはThe Update Framework(以下、TUF)に則って、Google Cloud Storageからダウンロードしているようです。
co := &cosign.CheckOpts{ RootCerts: fulcio.GetRoots(), CertEmail: certEmail, CertOidcIssuer: certOidcIssuer, }
https://github.com/sigstore/cosign/blob/v1.7.2/cmd/cosign/cli/verify/verify_blob.go#L200-L204
TUFはリポジトリや署名キーの侵害から保護する、安全なソフトウェアアップデートを実現するためのフレームワークとのことです(あんまり詳しく調べていません)
「じゃあ最初からTUFでバイナリの公開鍵を配布すればいいじゃん」とも思うかもしれません。確かにそれができればsigstoreを使う理由は無いわけですが、メンテナによる秘密鍵の管理が面倒な問題は解決しません。代わりにFulcioが面倒な秘密鍵の管理を行ってくれているおかげで、我々は秘密鍵の管理から解放されているわけですね。
攻撃3: X509v3 extensionsに埋め込まれる本人情報のなりすまし
さて、Tログの公開鍵の信頼性はFulcioの証明書発行に懸かっていることがわかりました。既に発行された証明書を偽装するのは困難なので、発行時に使われる本人情報を偽装して、なりすました結果を元にFulcioに証明書を発行させられないか考えてみます。
しかし、これはOpenID Connect(以下、OIDC)によって成立しません。X509v3 extensionsに埋め込まれる本人情報はOIDCによって生成されたIDトークンの属性値であり、これを発行できるのはFulcioが許可しているOIDCプロバイダしかありません。つまり、GitHub、Google、Microsoftアカウントで認証できない限り、なりすますことはできません。
ところで、GitHubで認証できることをメンテナの確認に使っているのであれば、前述のアクセストークンの流出と同じことが起きるのではないか?と思うかもしれません。しかし、アクセストークンでは認証はできないですし、二段階認証を有効化していれば、検証をしないよりは安全になると思います。たぶん...
攻撃4: Fulcioを侵害し、不正な証明書を発行させる
次の攻撃は、Fulcio自体を侵害し、不正に証明書を発行させる方法です。何らかの脆弱性を突き、IDトークン以外の値を使って証明書を発行できたとします。
これを防ぐ仕組みがCertificate Transparency Log(以下、CTログ)です。ざっと説明すると、認証局が発行した証明書の記録を、誰でも閲覧できるログに残すことで、証明書の不正な発行をいち早く検知できるようにする、というものです。以下のブログが参考になりました。
CTログは不正な証明書の発行を防ぐものではありませんが、CTログへの登録を不正に回避していないかどうかは、Signed Certificate Timestamp(以下、SCT)を使って確認できます。Cosignでは、ValidateAndUnpackCert
の中で確認しています(この実装はv1.7.2には含まれていません。Fulcioが発行する証明書にもSCTは含まれていないようですし、FulcioはまだCTログを登録してない?)
contains, err := ctl.ContainsSCT(cert.Raw) if err != nil { return nil, err } if co.EnforceSCT && !contains { return nil, errors.New("certificate does not include required embedded SCT") } if contains { // handle if chains has more than one chain - grab first and print message if len(chains) > 1 { fmt.Fprintf(os.Stderr, "**Info** Multiple valid certificate chains found. Selecting the first to verify the SCT.\n") } if err := ctl.VerifyEmbeddedSCT(context.Background(), chains[0]); err != nil { return nil, err } }
攻撃5: RekorのTログを改ざんする
さて、これでFulcioへの攻撃も難しいことがわかりました。次に攻撃者が狙うとしたら、Rekorでしょうか。Tログを改ざんしても、証明書を偽装できないので攻撃はかなり難しいですが、仮にFulcioの秘密鍵を手に入れたとして、それで署名した不正な証明書での既存のTログの改ざんを考えます。
これを防ぐのが、Merkle TreeとSigned Entry Timestamp(以下、SET)です。Merkle TreeはTログの各エントリのハッシュを葉とする木構造であり、親ノードは子ノードのハッシュから計算され...というのを繰り返して、最終的に根を計算します。根はRekorの秘密鍵によって署名されており、Tログが改ざんされると、根のハッシュ値が変わってしまうため、改ざんを検知できます。
Cosignはこのツリーの検証をcosign.VerifyTLogEntry
で行っています。
hashes := [][]byte{} for _, h := range e.Verification.InclusionProof.Hashes { hb, _ := hex.DecodeString(h) hashes = append(hashes, hb) } rootHash, _ := hex.DecodeString(*e.Verification.InclusionProof.RootHash) entryBytes, err := base64.StdEncoding.DecodeString(e.Body.(string)) if err != nil { return err } leafHash := rfc6962.DefaultHasher.HashLeaf(entryBytes) // Verify the inclusion proof. v := logverifier.New(rfc6962.DefaultHasher) if err := v.VerifyInclusionProof(*e.Verification.InclusionProof.LogIndex, *e.Verification.InclusionProof.TreeSize, hashes, rootHash, leafHash); err != nil { return errors.Wrap(err, "verifying inclusion proof") }
https://github.com/sigstore/cosign/blob/v1.7.2/pkg/cosign/tlog.go#L314-L331
SETはSCTと似ていますが、証明書ではなくTログに対するタイムスタンプです。RekorでもFulcioのCTログ同様に、署名のログはすべて記録されています。TUFでRekorの公開鍵を取得し、SETに対して検証することで、不正なTログを登録できないようにします。
Cosignでは同じくcosign.VerifyTLogEntry
で確認しています。
var entryVerError error for _, pubKey := range rekorPubKeys { entryVerError = VerifySET(payload, []byte(e.Verification.SignedEntryTimestamp), pubKey.PubKey) // Return once the SET is verified successfully. if entryVerError == nil { if pubKey.Status != tuf.Active { fmt.Fprintf(os.Stderr, "**Info** Successfully verified Rekor entry using an expired verification key\n") } return nil } } return errors.Wrap(entryVerError, "verifying signedEntryTimestamp")
https://github.com/sigstore/cosign/blob/v1.7.2/pkg/cosign/tlog.go#L359-L370
結論
CosignがKeyless Signingで検証していることをまとめます。
- ファイルのハッシュから対応するRekorのTログを取得
- Tログに埋め込まれた証明書の証明書チェーンを検証して、Fulcioから発行されていることを確認
- 証明書のX509v3 extensionsに埋め込まれたOIDC IDトークンの属性値を確認
- 証明書に埋め込まれたSCTで、FulcioがCTログに記録した証明書であることを確認
- 証明書の公開鍵で署名を検証
- RekorのTログのInclusion proofを検証し、Tログが改ざんされていないことを確認
- RekorのTログに埋め込まれたSETで、Rekorが正規に登録したログであることを確認
- 証明書が有効な期間中にRekorのTログが登録されたことを確認
検証側に求められることは膨大ですが、多くの技術が組み合わさって、特定の秘密鍵を必要としない署名ができるのは面白いです。
まだ開発段階ということで、Tログは予告なしにリセットされる可能性があったり、RekorやFulcioの運用はベストエフォートだったりと、完全にPGP署名を置き換えられるような状態では無いと思います。しかし、既にPGP署名を提供している場合には、とりあえず試してみる価値はあるのではないでしょうか。私のメンテしているTFLintでは、早速採用しました。GoReleaser + GitHub Actionsだと、数行程度で簡単に対応できるのでおすすめです。
GitHub ActionsをOIDCプロバイダとして利用する場合、利用者は証明書に埋め込まれたリポジトリ名を検証する必要があるのですが、Cosign v1.7.2ではまだこの属性の確認には対応していないようです。議論は行われているので、対応を待ちましょう(何か貢献できると良いのですが...)
参考
- https://knqyf263.hatenablog.com/entry/2022/02/06/213003
- https://blog.flatt.tech/entry/sigstore_keyless_signing
- https://github.com/sigstore/cosign
- https://github.com/sigstore/cosign/blob/v1.7.2/cmd/cosign/cli/verify/verify_blob.go#L187
- https://qiita.com/TakahikoKawasaki/items/4c35ac38c52978805c69
- https://theupdateframework.io/
- https://blog.jxck.io/entries/2018-03-27/certificate-transparency.html
- https://transparency.dev/verifiable-data-structures/