PGP/GPGについての情報整理
PGP
について曖昧な知識で済ませていましたが、きちんと理解するために情報を整理したメモを残します。GPG
が誤字ではないかと思った人はともだちです。
PGPとは
PGP(Pretty Good Privacy)
は、公開鍵暗号と共通鍵暗号を組み合わせて、データの暗号化、署名、検証ができるセキュリティソフトウェアです。
1991年にPhil Zimmermann氏によって開発・公開され、非商用利用は無償のフリーウェアとして提供されていました。商用ライセンスはZimmermann氏が設立したPGP社によって販売され、その後幾度かの買収を経て、2024年8月現在はBroadcom社がPGP
の知的財産を保有しています。
PGP
の仕様はRFC 1991として公開され、これを基にOpenPGPとして標準化されて現在も広く使用されています。
OpenPGP
OpenPGPは、PGP
をベースとした公開鍵暗号方式に基づくデータ暗号化と認証の標準フォーマットです。IETF
のOpenPGPワーキンググループによって標準化され、1998年にRFC 2440として公開されました。
その後、2007年にはRFC 4880によって更新され、さらにRFC 5581やRFC 6637などの各種RFCにより仕様が拡張されました。2024年7月には、これらの関連RFCを統合した最新仕様としてRFC 9580が公開されています。
GPG(GnuPG)
GPG(GnuPG, GNU Privacy Guard)は、OpenPGP
に完全準拠したPGPのオープンソース実装の1つであり、GNUプロジェクトの一環として開発されました。GPG
は特許で保護されたアルゴリズムを避けつつ、無償で多くの環境で使用できるようにすることで広く普及し、個人や組織が手軽にセキュリティを強化する手段として利用されています。
GPG
は特許で保護されたアルゴリズムを含めない方針をとっており、初期のバージョンではPGP
標準で採用されていたIDEA(International Data Encryption Algorithm)
やRSA
を使用できませんでした。2024年現在では特許権が失効しており、これらのアルゴリズムは使用可能になっています。
用語の使われ方
PGP
は暗号化ソフトウェアの名称であり、狭義のPGP
はこのソフトウェアを指します。しかし、PGP
の普及と発展に伴い、PGP
が指し示す範囲は広がりました。広義のPGP
としては、OpenPGP
を含むPGP
の仕様やその各種実装を含めた技術全体を指すと考えてよいでしょう。
一方、GPG
はOpenPGP
に準拠しており、GPG ⊆ OpenPGP ⊆ PGP
という包含関係を考えると、「PGP
の鍵を作成」することは「GPG
で鍵を作成する」ことで満たされ、「PGP
の公開鍵を登録」することは「GPG
で作成した公開鍵を登録する」ことで達成できます。
PGP/GPGの周辺技術・用語
OpenPGP
では鍵管理の仕様は定義されておらず、各実装に任されています。ここでの解説ではGPG
に特化した仕様を含みます。
鍵の機能
GPG
の鍵には、以下の4つの機能(capability)のいずれか、または複数を持たせることができます。
機能 | 説明 |
---|---|
Certify(証明) | 公開鍵が特定のユーザに属することを証明するために署名します |
Sign(署名) | メッセージやドキュメントにデジタル署名を行い、内容の改ざん検知や送信者の正当性を証明します |
Authenticate(認証) | ユーザが鍵の正当な所有者であることを確認します |
Encrypt(暗号化) | メッセージやデータを暗号化して、第三者に内容を秘匿します |
主鍵と副鍵
GPG
の鍵は主鍵(Primary Key
)と副鍵(Sub Key
)に分けられます。主鍵と副鍵の主な違いは、Certify
機能を持つかどうかで、主鍵のみがCertify
の機能を持ちます。主鍵はmaster key
とも呼ばれます。
公開鍵暗号では、公開鍵の信頼性が重要な要素となります。しかし、鍵が漏洩したり、不正利用された場合、新しい鍵ペアを作成する必要があり、公開鍵の信頼性が損なわれます。このとき、主鍵で認証署名された副鍵を使用していれば、主鍵が漏洩しない限り、新しい副鍵を作成して署名することで信頼性は維持されます。
主鍵はCertify
、Sign
、Authenticate
の機能を、副鍵はSign
、Authenticate
、Encrypt
の機能を持つことができます。主鍵が漏洩するとすべての鍵の有効性が失われるため、通常は主鍵にはCertify
機能のみを持たせてオフラインで物理的に安全な場所に保管しておくことが望ましいでしょう。
署名や暗号化などの日常的な用途は副鍵で行います。用途ごとに鍵を分けておくことで、万が一漏洩した場合でも影響範囲を限定できるなどセキュリティとキー管理の柔軟性が向上します。
公開鍵について
公開鍵暗号方式についての詳細はここでは省略しますが、公開鍵暗号では公開鍵と秘密鍵のペアが使用されます。主鍵と副鍵についても、それぞれに対応する公開鍵と秘密鍵が作成されますが、公開鍵をエクスポートする際には、副鍵の公開鍵は主鍵の公開鍵と一緒にエクスポートされます。これにより、主鍵の公開鍵が信頼されている限り、副鍵の公開鍵が変更されても信頼性が維持されます。
GPG
では、特に指定しない限り、公開鍵をエクスポートする際にすべての鍵の公開鍵がエクスポートされます。このため、副鍵を複数作成した場合でも、公開鍵は通常1ファイルとして扱われることが多いでしょう。
鍵の有効期限
OpenPGP
では主鍵と副鍵それぞれに異なる有効期限を設定できます。
主鍵は継続的に証明に用いられるため、通常は無期限で運用されることが多いでしょう。一方、副鍵は比較的容易に再作成が可能なため、任意の期限を設定できます。期限が到来しても、鍵の有効期限は延長できます。
有効期限の設定は、鍵管理のコストとセキュリティのバランスを考慮する必要があります。たとえば、Yubikeyのようなデバイスを使用する場合、認証デバイスのセキュリティ強度や運用面での利便性を考慮して、副鍵についても無期限で運用する選択肢が考えられます。
FingerprintとKey ID
各鍵は Fingerprint
と呼ばれるハッシュ値で一意に識別されます。Fingerprint
は公開鍵の情報をもとに計算されるSHA-1ハッシュで[1]、鍵の一意性や正当性の確認に使用できます。
また、鍵に対する操作対象の指定などでも、この Fingerprint
を用いて指定をします。
副鍵を含めた各鍵の Fingerprint
を表示するには --with-subkey-fingerprint
オプションを指定します。各鍵の2行目に出力されているハッシュ値が Fingerprint
を示し、ここでは ABD16A9E824711BD1D3991EB49ABEB4CA549A419
が主鍵の Fingerprint
となります。
$ gpg --list-keys --with-subkey-fingerprint
[keyboxd]
---------
pub ed25519 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
uid [ultimate] Alice <alice@example.com>
sub cv25519 2024-08-16 [E]
2110C85282B2A8AC19B1BC59F17DBE6902AC1669
sub ed25519 2024-08-16 [A]
9EC1414FB2C9D390072411047FFE7739A488A81C
Fingerprint
のより短い表現として、下位32bitまたは下位64bitのみを切り出した Key ID
も指定できます。
--keyid-format
を付加して鍵一覧を表示した際に、暗号アルゴリズムと併記して出力されるハッシュ値が Key ID
です。主鍵の Key ID
は A549A419
または 49ABEB4CA549A419
が出力されており、これは Fingerprint
の下位部分に一致することが分かります。
Key ID
はデータ長の短さから、取り回しには便利ですが衝突の可能性は高まります。 Key ID
で鍵が一意に特定できない場合には Fingerprint
を使用します。また、鍵の識別情報として外部に公開する場合には、通常 Key ID
ではなく Fingerprint
を共有することが望ましいでしょう。
$ gpg --list-keys --keyid-format=short
[keyboxd]
---------
pub ed25519/A549A419 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
uid [ultimate] Alice <alice@example.com>
sub cv25519/02AC1669 2024-08-16 [E]
sub ed25519/A488A81C 2024-08-16 [A]
$ gpg --list-keys --keyid-format=long
[keyboxd]
---------
pub ed25519/49ABEB4CA549A419 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
uid [ultimate] Alice <alice@example.com>
sub cv25519/F17DBE6902AC1669 2024-08-16 [E]
sub ed25519/7FFE7739A488A81C 2024-08-16 [A]
Fingerprint
や Key ID
は公開鍵をもとにしたハッシュ値であるため公開情報であり、たとえばプログラム内に直接記載しても問題ありません。
失効証明書
鍵が漏洩した場合や不要になった場合、鍵を無効化するには失効証明書が必要です。通常は主鍵と同様の安全な場所に保管することが推奨されます。
信頼の輪(Web of Trust)
公開鍵暗号方式では、公開鍵がどのユーザのものであるかを証明することが重要ですが、この認証プロセスには困難も伴います。
そこで、PGPでは、互いに信頼する利用者同士が公開鍵に署名し、信頼関係を確立する「信頼の輪(Web of Trust)」という仕組みを採用しています。この仕組みによって、「信頼関係のある相手が信頼した公開鍵は信頼できる」という考え方が成り立ち、直接の信頼関係がない相手も第三者を介して信頼することが可能になります。信頼の輪は、1992年に登場したPGP 2.0から提唱されており、相互に信頼された公開鍵が広く配布され、信頼度が蓄積されることで分散型ネットワークの構築が期待されています。
公開鍵の認証署名は、その公開鍵が実際にそのユーザのものであることを確認する必要があるため、ユーザ同士で集まり相互に署名する「キーサインパーティ」などのイベントが開催されます。
信頼の輪は、鍵管理や署名のプロセスに一定の技術的な知識を要求するため広く普及しているとは言えず、主にLinuxユーザーグループなど、小規模なコミュニティ内で運用されることが多いです。
公開鍵基盤(PKI)
公開鍵基盤(PKI, Public Key Infrastructure)は、公開鍵暗号を使用して安全な通信や認証を実現するための仕組みを指します。具体的なシステムというより、仕組み自体を表す用語です。
一般的な構造としては、第三者機関である認証局が発行したデジタル証明書によって、その公開鍵と特定のユーザの関連付けを保証し、利用者はその認証局を信頼することで、公開鍵の信頼性を確保する仕組みを表します。分散型信頼モデルである「信頼の輪(Web of Trust)」を広義の公開鍵基盤に含めることもありますが、多くの場合、公開鍵基盤は集中型信頼モデルを指します。
通常、認証局は国際的な監査基準などを満たした信頼できる組織であり、利用者はその認証局を信頼することで安全な通信を確立し、通信相手の身元を認証できます。この点で、集中型信頼モデルは使いやすい仕組みと言えるでしょう。
私たちが日常的に利用するWebサイトのSSL証明書も、同様の仕組みで公開鍵の信頼性を担保しています(ここで言う「信頼」とは、公開鍵の所有者が誰であるかを保証することを指し、その所有者自体の安全性を保証するものではありません)。日常的に意識することはほとんどありませんが、国際的な監査基準を満たした認証局のルート証明書を主要ブラウザが信頼しているため、利用者は暗黙のうちに一定以上の信頼を得た証明書を使用しています。
最終的には、利用者がブラウザの配布元を信頼することで成り立つ仕組みであるため、信頼できないブラウザを使用する場合は、そのリスクを考慮する必要があります。
公開鍵証明書の広く採用されている規格にはX.509
があり、この規格に準拠した証明書はX.509証明書
と呼ばれます。X.509証明書
は、インターネット上で広く使われており、特にSSL/TLSの通信において重要な役割を果たしています。
キーサーバ
キーサーバは、公開鍵の登録・検索サービスを提供するサーバです。利用者は、自分の公開鍵をキーサーバにアップロードすることで第三者に鍵を配布でき、安全な通信に必要な公開鍵を簡単に入手できます。
キーサーバは登録された鍵の信頼性を保証しないため、前述の信頼の輪(Web of Trust)や公開鍵基盤(PKI)などで、信頼性を確認する必要があります。
広く利用されているキーサーバとしては、keys.openpgp.orgやkeyserver.ubuntu.comなどがあります。
キーサーバと類似の機能を提供するサービスもいくつか存在します。E2EE(End-to-end Encryption)
のメッセージ・ファイル共有サービスであるkeybaseは、公開鍵とSNSアカウントやドメインを紐づけて登録することで、キーサーバおよび公開鍵基盤としての機能を提供します。
また、GitHubではGPG鍵の登録が可能で、その公開鍵は第三者がアクセス可能です。GitHub
のアカウントと直接紐づいていることから、公開鍵基盤としての役割も果たしますが、登録された公開鍵は主にGitHub
内での署名検証に使用されるため、厳密にはキーサーバや公開鍵基盤とは言い難いでしょう。
PGP/GPGの鍵管理
PGP/GPGでの鍵管理について、具体的な手順を基に例示していきます。記載したコマンド例の作業環境はmacOS Ventura 13.5
、GPG(GnuPG) 2.4.5
を想定しています。
GPGのインストール
GPG(GnuPG)のインストールは公式サイトのダウンロードページから環境別のバイナリをダウンロードします。
プラットフォームに応じてパッケージマネージャを介してインストールすると簡単に導入できます。macOSではHomebrewを使用して以下のコマンドでインストールできます。
brew install gpg
さらに、macOSではpinentry-macのインストールも推奨されます。pinentryは、安全にPINやパスフレーズを入力するためのユーティリティプログラムであり、各種環境向けのインターフェースを提供し、入力情報がディスクに保存されたりスワップされないように配慮されています。
標準ではターミナル上のテキストユーザインターフェースで入力ダイアログを扱う pinentry-curses
が利用可能です。pinentry-mac
はmacOS向けのGUIを提供し、Keychainとの連携などの機能も備えています。
以下のコマンドでpinentry-macをインストールし、gpg-agentに設定できます。
brew install pinentry-mac
echo "pinentry-program $(which pinentry-mac)" >> ~/.gnupg/gpg-agent.conf
gpgconf --reload gpg-agent
GUIを必要としない場合は pinentry-curses
でも十分ですが、複数タブを利用するターミナル環境では、 gpg-agent
がプロンプトを表示する対象を正しく判断できないことがあります。この問題を回避するには、以下のように使用中の端末を都度 gpg-agent
に通知する必要があります。
gpg-connect-agent updatestartuptty /bye
pinentry-mac
を使用すれば、これらの煩雑な手順や設定作業を省略できるため、より便利に利用できます。
鍵の作成
GPG鍵の新規作成(主鍵の作成)
既存のGPGキーがない場合、以下のコマンドで新しいGPG鍵ペアを作成します。
gpg --full-generate-key
--full-generate-key
は新しい鍵ペアをインタラクティブに作成するオプションです。このコマンドを実行すると、対話形式で鍵の種類やアルゴリズム、有効期限などを指定するインターフェースが表示されます。設定内容が既に決まっている場合は、ファイルから指定を読み込む --generate-key --batch
や、コマンドラインオプションで指定する --quick-generate-key
を使用することで、非インタラクティブな鍵の作成も可能です。
以下に、コマンドの実行結果の例を示します。なお、より詳細な鍵のカスタマイズが必要な場合は --expert
オプションを使用できますが、ここでは基本的な作成手順に絞ります。
$ gpg --full-generate-key
gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: directory '/Users/alice/.gnupg' created
Please select what kind of key you want:
(1) RSA and RSA
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(9) ECC (sign and encrypt) *default*
(10) ECC (sign only)
(14) Existing key from card
Your selection? 9
Please select which elliptic curve you want:
(1) Curve 25519 *default*
(4) NIST P-384
(6) Brainpool P-256
Your selection? 1
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: Alice
Email address: alice@example.com
Comment:
You selected this USER-ID:
"Alice <alice@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
この例では、鍵の種類を ECC (sign and encrypt)
、楕円曲線は Curve 25519
、有効期限は 無期限(0)
として作成しています。
ECC (sign and encrypt)
は認証機能を持つ主鍵と暗号化の機能を持つ副鍵がそれぞれ作成されます。楕円曲線はデフォルトの Curve 25519
で通常は問題ありません。Curve 25519
は高速で安全性が高く、鍵サイズも小さいため、モバイルデバイスや組み込みシステムにも適しています。以前はRSA
がデフォルトとされていましたが、最新バージョンでは高速な楕円曲線暗号で鍵長の短い ECC
+ Curve 25519
の組み合わせがデフォルトとなっています。
ここまで作業を進めるとパスフレーズの入力ダイアログが表示されるため、任意のパスフレーズを入力します。
gpg: /Users/alice/.gnupg/trustdb.gpg: trustdb created
gpg: directory '/Users/alice/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/Users/alice/.gnupg/openpgp-revocs.d/ABD16A9E824711BD1D3991EB49ABEB4CA549A419.rev'
public and secret key created and signed.
pub ed25519 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
uid Alice <alice@example.com>
sub cv25519 2024-08-16 [E]
これで鍵作成の初期作業が完了しました。以下のものが作成されます。
- 主鍵(署名/ed25519)
- 副鍵(暗号化/Curve 25519)
- 失効証明書
作成した鍵は --list-keys
または --list-secret-keys
で確認できます。
$ gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
[keyboxd]
---------
pub ed25519 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
uid [ultimate] Alice <alice@example.com>
sub cv25519 2024-08-16 [E]
--list-keys
は公開鍵の一覧を表示します。pub
と出力されているものが主鍵の公開鍵で、sub
が副鍵を示します。
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
は Fingerprint
と呼ばれるもので、以降もこの鍵を特定するための識別子として頻繁に使われます。
$ gpg --list-secret-keys
[keyboxd]
---------
sec ed25519 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
uid [ultimate] Alice <alice@example.com>
ssb cv25519 2024-08-16 [E]
--list-secret-keys
は秘密鍵の一覧を表示します。sec
と出力されているものが主鍵の秘密鍵で、sub
が副鍵を示します。
公開鍵の出力
公開鍵の出力には --export
オプションを指定します。そのままではバイナリ形式で出力されるため、通常は --armor
を付加して ASCII Armor
形式で出力します。
ASCII Armor
形式は、バイナリデータをテキスト形式に変換するためのフォーマットです。具体的にはデータをRadix-64と呼ばれるbase64
エンコードとchecksum
で構成されるフォーマットに変換し、これにエンコード種別を示すヘッダを追加したものです。ヘッダ部はPEMエンコーディングやRFC7468のテキストエンコーディングに類するBEGIN/END行で囲われる形式です。
具体的な出力例は以下のようになります。特に指定のない場合、出力された公開鍵には主鍵とすべて副鍵の公開鍵が含まれます。
$ gpg --export --armor ABD16A9E824711BD1D3991EB49ABEB4CA549A419
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEZr9i8RYJKwYBBAHaRw8BAQdAxXdjoE3lftnDHfyREJzlpodSn5/B9aGcWTpK
oP9uFBq0GUFsaWNlIDxhbGljZUBleGFtcGxlLmNvbT6IkwQTFgoAOxYhBKvRap6C
RxG9HTmR60mr60ylSaQZBQJmv2LxAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4H
AheAAAoJEEmr60ylSaQZLJYBAOJJUQfqyxX/3CR0eOs/bge1rf0ufC/qsZmCtl4g
vOI8AQDlWvEkKFdQMTqzjl9RJoRbDgOpEo3gHCY5tvdI7eBFBrg4BGa/YvESCisG
AQQBl1UBBQEBB0Ar5Zkz9DeLLbQoKqVFIZ58UxOHnyiko4qyX/3WWLV0YwMBCAeI
eAQYFgoAIBYhBKvRap6CRxG9HTmR60mr60ylSaQZBQJmv2LxAhsMAAoJEEmr60yl
SaQZgPQBALVUW/RuEsEpBW/Ir1gCO6xolQVjTSdpPXYSXZVb/SkXAP9op5g7hzco
1mTj4ivftCFsxQnsqommzcfIKVXHo3WuBrgzBGa/avcWCSsGAQQB2kcPAQEHQON1
Gr+b88buOSrtztZ5MbwLsxKherAJeOCTXRc3OEZ5iHgEGBYKACAWIQSr0WqegkcR
vR05ketJq+tMpUmkGQUCZr9q9wIbIAAKCRBJq+tMpUmkGebDAQCfJuHPKbujdWIT
SHiRMuyIUJah1qjjWXfDUuzrpov02wD/bAEvtATQxpZA1jIZ9eujEGgohnUy4zVQ
OdvEJnVGUAY=
=Fu5D
-----END PGP PUBLIC KEY BLOCK-----
--output
オプションと出力先ファイル名を指定すると、公開鍵は標準出力ではなく指定のファイルパスに出力されます。これは、公開鍵を他者と共有する際に便利です。
$ gpg --export --armor --output alice.gpg ABD16A9E824711BD1D3991EB49ABEB4CA549A419
副鍵の追加
OpenSSHで使用できる認証(Authenticate)用途の副鍵を作成します。これにより、SSHキーとしてGPG鍵を使用することが可能になり、鍵の管理を一元化できます。副鍵を追加するには、 Fingerprint
を指定して --edit-key
オプションを使用し、鍵の編集モードを起動します。
$ gpg --expert --edit-key ABD16A9E824711BD1D3991EB49ABEB4CA549A419
gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec ed25519/49ABEB4CA549A419
created: 2024-08-16 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/F17DBE6902AC1669
created: 2024-08-16 expires: never usage: E
[ultimate] (1). Alice <alice@example.com>
addkey
コマンドを使って新しい副鍵を追加します。まず、追加する鍵の種類を選択します。ここでは、 (11) ECC (set your own capabilities)
を選び、ECC鍵に対して機能を指定していきます。
gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
(14) Existing key from card
Your selection? 11
初期状態では Sign
の機能が設定されています。今回は Authenticate
の機能のみ必要なので、画面の指示に従って Sign
を無効化し、 Authenticate
を有効化します。
Possible actions for this ECC key: Sign Authenticate
Current allowed actions: Sign
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? s
Possible actions for this ECC key: Sign Authenticate
Current allowed actions:
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? a
Possible actions for this ECC key: Sign Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
次に、暗号曲線の選択と有効期限を指定します。
Please select which elliptic curve you want:
(1) Curve 25519 *default*
(2) Curve 448
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
有効期限に無期限を選択すると確認が求められますが、ここでは無期限のまま作成します。最後の確認にも「y」と答え、パスフレーズを入力すると、鍵の作成が完了します。
sec ed25519/49ABEB4CA549A419
created: 2024-08-16 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/F17DBE6902AC1669
created: 2024-08-16 expires: never usage: E
ssb ed25519/7FFE7739A488A81C
created: 2024-08-16 expires: never usage: A
[ultimate] (1). Alice <alice@example.com>
gpg> save
usage: A
と表示されている認証機能を持った副鍵が作成されました。 save
コマンドで鍵を保存してください。
GPGのプロンプトを終了するには、 quit
コマンドを使用します。この際、未保存のデータがある場合には保存するか確認されるため、必要なデータは忘れずに保存しましょう。
SSH公開鍵の出力
Fingerprint
を指定して --export-ssh-key
オプションを使用すると、GPG鍵からSSH互換の公開鍵を出力できます。
$ gpg --export-ssh-key ABD16A9E824711BD1D3991EB49ABEB4CA549A419
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAION1Gr+b88buOSrtztZ5MbwLsxKherAJeOCTXRc3OEZ5 openpgp:0xA488A81C
この出力をそのまま ~/.ssh/authorized_keys ファイルに追加することで、SSH認証に使用できます。
コマンドラインのみでの鍵作成
非インタラクティブに主鍵を作成する場合には --quick-generate-key
オプションを指定します。これは、スクリプトでの自動化や、事前に設定を決めている場合に便利です。
暗号アルゴリズム(ALGO)や鍵の用途(USAGE)を指定しない場合には default
を指定します。いずれかが指定された場合には主鍵のみ、どちらも default
が指定された場合には認証用の主鍵と署名用の副鍵が作成されます。
$ gpg --quick-generate-key
usage: gpg [options] --quick-generate-key USER-ID [ALGO [USAGE [EXPIRE]]]
# ALGO, USAGE, EXPIRE を指定する例
# この例では、Ed25519アルゴリズムを使用し、証明(cert)用途で、有効期限なし(0)の鍵を生成しています
$ gpg --quick-generate-key "Alice <alice@example.com>" "ed25519" "cert" 0
副鍵を作成する場合には --quick-add-key
オプションを指定します。主鍵の作成とは異なり、指定するのは user-id
ではなく fingerprint
になります。これは、副鍵が特定の主鍵に紐づくものであることを明示するためです。
$ gpg --quick-add-key
usage: gpg [options] --quick-add-key FINGERPRINT [ALGO [USAGE [EXPIRE]]]
# ALGO, USAGE, EXPIRE を指定する例
$ gpg --quick-add-key "ABD16A9E824711BD1D3991EB49ABEB4CA549A419" "ed25519" "sign" 0
複数user-idを登録する
プライベートと仕事用など複数の異なるメールアドレスで鍵を運用したいケースがあります。この場合は鍵にuser-id
を追加できます。これにより、同一の鍵ペアを複数のアイデンティティで使用できるようになります。
user-id
を追加するには、まず --edit-key
オプションを使用して鍵の編集モードを起動します。
$ gpg --edit-key ABD16A9E824711BD1D3991EB49ABEB4CA549A419
gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
sec ed25519/49ABEB4CA549A419
created: 2024-08-16 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/F17DBE6902AC1669
created: 2024-08-16 expires: never usage: E
ssb ed25519/7FFE7739A488A81C
created: 2024-08-16 expires: never usage: A
ssb ed25519/3D0336068782EB4C
created: 2024-08-19 expires: never usage: S
[ultimate] (1). Alice <alice@example.com>
gpg> adduid
Real name: Bob
Email address: bob@example.com
Comment:
You selected this USER-ID:
"Bob <bob@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
sec ed25519/49ABEB4CA549A419
created: 2024-08-16 expires: never usage: SC
trust: ultimate validity: ultimate
ssb cv25519/F17DBE6902AC1669
created: 2024-08-16 expires: never usage: E
ssb ed25519/7FFE7739A488A81C
created: 2024-08-16 expires: never usage: A
ssb ed25519/3D0336068782EB4C
created: 2024-08-19 expires: never usage: S
[ultimate] (1) Alice <alice@example.com>
[ unknown] (2). Bob <bob@example.com>
この手順はGitHubのGPG キーとメールの関連付けのドキュメントにも記載されています。
GitHubの場合、アカウントに関連付けられた検証済みのメールアドレスと紐づけられている必要があります。
公開鍵のインポート
他人の公開鍵をインポートすることで、そのユーザの署名検証や暗号化メッセージの作成が可能になります。公開鍵のインポートには --import
オプションを使用します。
$ gpg --import public_key.asc
キーサーバ経由でも公開鍵を入手できます。以下の例はRabbitMQの公式ドキュメントにも記載のある公開鍵の取り込み手順です。
$ gpg --keyserver "hkps://keys.openpgp.org" --recv-keys "0A9AF2115F4687BD29803A206B73A36E6026DFCA"
$ gpg --list-keys
[keyboxd]
---------
pub rsa4096 2016-05-17 [SC]
0A9AF2115F4687BD29803A206B73A36E6026DFCA
uid [ unknown] RabbitMQ Release Signing Key <info@rabbitmq.com>
sub rsa4096 2016-05-17 [E]
pub ed25519 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
uid [ultimate] Bob <bob@example.com>
uid [ultimate] Alice <alice@example.com>
sub cv25519 2024-08-16 [E]
sub ed25519 2024-08-16 [A]
sub ed25519 2024-08-19 [S]
インポート対象の公開鍵はfingerprintを直接確認するなど誤った鍵をインポートしないように注意します。キーサーバ経由でインポートする場合には信頼できるキーサーバを選択しましょう。また、キーサーバから取得した鍵の信頼性は別途確認する必要があります(キーサーバは鍵の真正性を保証するものではありません)。
インポートした直後の公開鍵は信頼度が未設定で unknown
と表示されます。これは、GPGがこの鍵の信頼性を判断できないことを意味します。個人利用での限定的な用途ではあまり必要性が感じられないこともありますが、一応信頼度を設定しておきます。信頼度の設定は --edit-key
で信頼度設定のインターフェースを使用します。
$ gpg --edit-key 0A9AF2115F4687BD29803A206B73A36E6026DFCA
gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
pub rsa4096/6B73A36E6026DFCA
created: 2016-05-17 expires: never usage: SC
trust: unknown validity: unknown
sub rsa4096/9C93824E12EBCE19
created: 2016-05-17 expires: never usage: E
[ unknown] (1). RabbitMQ Release Signing Key <info@rabbitmq.com>
公開鍵に信頼度を設定するには、鍵の編集モードで trust
コマンドを実行して信頼度を選択します。第三者の公開鍵ですが、公式サイトでfingerprintを確認した一定の信頼度のある鍵だと考えられるので 4 = I trust fully
を指定します。
gpg> trust
pub rsa4096/6B73A36E6026DFCA
created: 2016-05-17 expires: never usage: SC
trust: unknown validity: unknown
sub rsa4096/9C93824E12EBCE19
created: 2016-05-17 expires: never usage: E
[ unknown] (1). RabbitMQ Release Signing Key <info@rabbitmq.com>
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
Your decision? 4
pub rsa4096/6B73A36E6026DFCA
created: 2016-05-17 expires: never usage: SC
trust: full validity: unknown
sub rsa4096/9C93824E12EBCE19
created: 2016-05-17 expires: never usage: E
[ unknown] (1). RabbitMQ Release Signing Key <info@rabbitmq.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.
trust: full
に表示が変わり、鍵の信頼度が設定されました。
この状態では有効性を示す validity
が unknown
のままで、GPGが鍵を使用するかの判断基準が不明のままとなっています。
インポートした公開鍵に署名することで真正性が保証され、validity
を向上させることができます。
手元の環境でのみ保証できていればよいので、外部には公開されない「ローカル署名」を行うために lsign
コマンドを実行します。ローカル署名は、その鍵が確かに意図した所有者のものであることを自分自身で確認したことを示すもので、他人と共有されることはありません。
gpg> lsign
pub rsa4096/6B73A36E6026DFCA
created: 2016-05-17 expires: never usage: SC
trust: full validity: unknown
Primary key fingerprint: 0A9A F211 5F46 87BD 2980 3A20 6B73 A36E 6026 DFCA
RabbitMQ Release Signing Key <info@rabbitmq.com>
Are you sure that you want to sign this key with your
key "Bob <bob@example.com>" (49ABEB4CA549A419)
The signature will be marked as non-exportable.
Really sign? (y/N) y
gpg> save
validity
の再計算は即時には行われないので、一度保存してから再度編集モードを起動して確認すると trust
と validity
がいずれも full
になっていることが分かります。user-id
に併記されている [ full ]
も validity
を示します。
pub rsa4096/6B73A36E6026DFCA
created: 2016-05-17 expires: never usage: SC
trust: full validity: full
sub rsa4096/9C93824E12EBCE19
created: 2016-05-17 expires: never usage: E
[ full ] (1). RabbitMQ Release Signing Key <info@rabbitmq.com>
鍵のバックアップと復元
秘密鍵を紛失すると、暗号化されたデータの復号や署名の作成ができなくなるため、適切にバックアップを行う必要があります。
鍵(主鍵+副鍵)のバックアップ
鍵をバックアップするには --export-secret-keys
オプションを使用します。このコマンドは秘密鍵をエクスポートします。秘密鍵には公開鍵の情報も含まれているため、秘密鍵をバックアップすれば公開鍵も復元できます。そのため、バックアップは秘密鍵のみで十分です。
この例では、ASCII Armored形式でファイルに出力します。出力した鍵は主鍵を含むため、QRコードに変換した上で印刷してオフラインで保管するなど安全に管理します。
$ gpg --export-secret-keys --armor --output private.key ABD16A9E824711BD1D3991EB49ABEB4CA549A419
鍵(副鍵)のバックアップ
副鍵のみをバックアップするには --export-secret-subkeys
オプションを使用します。
$ gpg --export-secret-subkeys --armor --output private-subkeys.key ABD16A9E824711BD1D3991EB49ABEB4CA549A419
副鍵のみをバックアップすることで、主鍵を安全なオフラインの場所に保管しつつ、日常的に使用する鍵(副鍵)のバックアップを別途管理できます。これにより、万が一副鍵が漏洩した場合でも、主鍵は安全に保たれます。
鍵のリストア
鍵をリストア(復元)するにはエクスポートされた秘密鍵をインポートします。公開鍵のインポートと同様に --import
オプションを使用します。
主鍵を退避して、副鍵のみで運用するために鍵をエクスポート/インポートする手順を以下に示します。流れとしては、すべての秘密鍵を削除してから副鍵のみの秘密鍵をインポートすることで主鍵の秘密鍵を除いた環境を構築できます。
# 秘密鍵をすべて削除
$ gpg --delete-secret-keys ABD16A9E824711BD1D3991EB49ABEB4CA549A419
# 副鍵のみの秘密鍵をインポート
$ gpg --import private-subkeys.key
# 秘密鍵の一覧を表示
$ gpg --list-secret-keys
[keyboxd]
---------
sec# ed25519 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
uid [ultimate] Bob <bob@example.com>
uid [ultimate] Alice <alice@example.com>
ssb cv25519 2024-08-16 [E]
ssb ed25519 2024-08-16 [A]
ssb ed25519 2024-08-19 [S]
主鍵の秘密鍵に sec#
のように #
がついているのは秘密鍵の実体が存在しないことを表します。この状態では、主鍵を使用する操作(新しい副鍵の作成、他の鍵への署名など)はできませんが、副鍵を使用した暗号化や署名などの日常的な操作は可能です。主鍵に関する操作が必要な場合は、安全に保管されている主鍵をインポートする必要があります。
GPGのディレクトリ構造
GPGの設定ファイルや鍵データは、通常 $GNUPGHOME/.gnupg
ディレクトリ内に格納されます。$GNUPGHOME
が設定されていない場合は、デフォルトで ~/.gnupg
が使用されます。以下はそのディレクトリ構造の一例です。
/Users/alice/.gnupg
├── common.conf # GPGの一般的な設定を保存するファイル
├── openpgp-revocs.d # 失効証明書を保存するディレクトリ
│ └── ABD16A9E824711BD1D3991EB49ABEB4CA549A419.rev
├── private-keys-v1.d # 秘密鍵を保存するディレクトリ
│ ├── 42C8A11340799CF88F745B5FF443A0734A623829.key
│ ├── C082C125437D924F41FA5BDCAC6FC820622FCC9E.key
│ └── EDAF4373719985F98C203FBA5AFEC6A055BE12EE.key
├── public-keys.d # 公開鍵リングのデータベースを保存するディレクトリ
│ ├── pubring.db
│ └── pubring.db.lock
└── trustdb.gpg # 鍵の信頼度情報を保存するデータベースファイル
秘密鍵のファイル名は、一覧表示時に --with-keygrip
オプションを使用することで Keygrip
として表示されます。Keygripは鍵を一意に識別するためのハッシュ値で、鍵の内容に基づいて生成されます。同じ鍵は常に同じKeygripを持つため、鍵の識別や管理に役立ちます。
$ gpg --list-secret-keys --with-keygrip
[keyboxd]
---------
sec ed25519 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
Keygrip = C082C125437D924F41FA5BDCAC6FC820622FCC9E
uid [ultimate] Alice <alice@example.com>
ssb cv25519 2024-08-16 [E]
Keygrip = 42C8A11340799CF88F745B5FF443A0734A623829
ssb ed25519 2024-08-16 [A]
Keygrip = EDAF4373719985F98C203FBA5AFEC6A055BE12EE
このように表示されたKeygripとディレクトリ内のファイル名を対応させることで、どのファイルがどの秘密鍵に対応しているかを確認できます。
GnuPG
の各種情報はすべてこのディレクトリに格納されるため、ディレクトリ全体をバックアップをすることも考えられますが、失効証明書など画含まれることからセキュリティ観点、ソケットなどを含む不要なファイルが含まれることなどから不適切だと言えるでしょう。
GPG鍵の管理を柔軟に行いたい場合、 $GNUPGHOME
環境変数を使用して一時的に異なる鍵セットを使用できます。これは、テスト用の鍵を作成する場合や、異なるプロジェクトで別々の鍵を使用したい場合に便利です。以下は、その使用例です。
$ GNUPGHOME=~/.gnupg-test gpg --edit-key ABD16A9E824711BD1D3991EB49ABEB4CA549A419
GPGを利用した各種作業
デジタル署名
デジタル署名は公開鍵暗号方式を利用した電子的な認証技術です。送信者の秘密鍵を用いて計算したメッセージのハッシュ値を、送信者の公開鍵で検証することにより、データの真正性(Authenticity)、完全性(Integrity)、否認防止(Non-repudiation)を確保できます。
- 真正性
- メッセージが送信者から来たものであることを保証します
- 署名を検証することで送信者の身元を確認でき、なりすましを防ぐことができます
- 完全性
- データが伝送中に変更されてないことを保証します
- 意図的または偶発的なデータの改竄を検知できます
- 否認防止
- 送信者が後からメッセージの送信を否定することを防止します
分離署名
分離署名は、元のデータとは別に署名ファイルを作成する手段です。元データが変更されないため、署名を認識しないソフトウェアなどでもデータを問題なく取り扱うことができます。
$ cat test.txt
This is a test document.
$ gpg --detach-sign test.txt
$ ls test.txt*
test.txt test.txt.sig
元のドキュメントはそのままに、署名ファイルとして test.txt.sig
が生成されました。これはバイナリファイルです。署名ファイルをテキスト形式で生成するには --armor
オプションを付加します。
$ gpg --detach-sign --armor test.txt
$ ls test.txt*
test.txt test.txt.asc test.txt.sig
$ cat test.txt.asc
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQTZ/yrwsATxrECrNTk9AzYGh4LrTAUCZsmQhgAKCRA9AzYGh4Lr
TJFmAPsGHxRSS4Hapc1u1wwDBqYcJ94zuc9Rb5pm50v9U2GQAAD9GGR7ePA9a8/c
cUS7ixKBDlujLCeWupf4sxIl0cph7QQ=
=IkwH
-----END PGP SIGNATURE-----
テキスト形式の署名ファイルは test.txt.asc
として生成されました。
データを受け渡しする際には、元データとともに署名ファイルを送信します。受信者は、送信者の公開鍵でこれを検証できます。署名の検証には --verify
オプションを使用します。
$ gpg --verify test.txt.asc test.txt
gpg: Signature made Sat Aug 24 16:49:26 2024 JST
gpg: using EDDSA key D9FF2AF0B004F1AC40AB35393D0336068782EB4C
gpg: Good signature from "Bob <bob@example.com>" [ultimate]
gpg: aka "Alice <alice@example.com>" [ultimate]
Good signature
と出力されており問題のないことが分かります。署名を検証するには、送信者の公開鍵をあらかじめインポートしておく必要があります。
クリアテキスト署名
クリアテキスト署名は、テキストファイルにのみ適用できる署名形式で、元のドキュメントに署名情報が付加された形式のデータを出力します。
メッセージと署名を1つのファイルとして取り扱うことにより管理が容易であり、メールやドキュメントなどで可読性を維持したまま真正性や完全性を保証できます。
$ gpg --clear-sign test.txt
$ ls test.txt*
test.txt test.txt.asc
$ cat test.txt.asc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
This is a test document.
-----BEGIN PGP SIGNATURE-----
iHUEARYKAB0WIQTZ/yrwsATxrECrNTk9AzYGh4LrTAUCZsmSoAAKCRA9AzYGh4Lr
TGz1AP4gUjb27N9oAoG5RFqGY9p7UTWi8G4xcaCVoH1jNksj4QD/Rm4AFHwwabY4
LWcew5F7u6aXsLrDOsnRH282IBMn1Qw=
=E6oS
-----END PGP SIGNATURE-----
元のメッセージと署名情報を含む test.txt.asc
が生成され、前半部には元のドキュメント、後半部にはPGP署名の記載されたデータが含まれます。署名の検証は --verify
オプションを使用します。
$ gpg --verify test.txt.asc
gpg: Signature made Sat Aug 24 16:58:24 2024 JST
gpg: using EDDSA key D9FF2AF0B004F1AC40AB35393D0336068782EB4C
gpg: Good signature from "Bob <bob@example.com>" [ultimate]
gpg: aka "Alice <alice@example.com>" [ultimate]
(埋め込み)署名
--sign
オプションを使用すると元データに署名の付加されたバイナリデータが生成されます。
$ gpg --sign test.txt
$ ls test.txt*
test.txt test.txt.gpg
--sign
で署名されたファイルを検証するには --verify
オプションが使用できますが、検証のみでは元データを復元できないため、通常は --decrypt
オプションを使用するとよいでしょう。
$ gpg --verify test.txt.gpg
gpg: Signature made Sun Aug 25 00:45:25 2024 JST
gpg: using EDDSA key D9FF2AF0B004F1AC40AB35393D0336068782EB4C
gpg: Good signature from "Bob <bob@example.com>" [ultimate]
gpg: aka "Alice <alice@example.com>" [ultimate]
$ gpg --decrypt test.txt.gpg
This is a test document.
gpg: Signature made Sun Aug 25 00:45:25 2024 JST
gpg: using EDDSA key D9FF2AF0B004F1AC40AB35393D0336068782EB4C
gpg: Good signature from "Bob <bob@example.com>" [ultimate]
gpg: aka "Alice <alice@example.com>" [ultimate]
--decrypt
オプションでは元データの復元と署名検証が行われていることが分かります。 decrypt
という単語は暗号化されたデータを復号することが想起されますが、GPGにおいては暗号化されていない署名付データから元データを復元する際にも使用されます(後述の暗号化付き署名でも同様のコマンドを使用します)。
署名+暗号化
--encrypt
オプションを併用すると、署名に加えて暗号化を行うことができます。暗号化では、受信者の公開鍵でデータを暗号化するため --recipient
オプションで受信者のuser-idを指定します。
$ gpg --sign --encrypt --recipient Bob test.txt
$ gpg --decrypt test.txt.gpg
gpg: encrypted with cv25519 key, ID F17DBE6902AC1669, created 2024-08-16
"Bob <bob@example.com>"
This is a test document.
gpg: Signature made Sun Aug 25 01:03:33 2024 JST
gpg: using EDDSA key D9FF2AF0B004F1AC40AB35393D0336068782EB4C
gpg: Good signature from "Bob <bob@example.com>" [ultimate]
gpg: aka "Alice <alice@example.com>" [ultimate]
GitHubのcommitへの署名
GPGでcommitに署名すると、GitHub上で Verified
のマークを表示できます。これにより、commitが正当な作成者のものであることが確信でき、悪意のあるcommitや第三者による不正なコードの混入を防げます。
詳しい解説や手順はGitHubの公式ドキュメントにも記載がありますが、既にGPG鍵を運用している場合は大きく以下の2点が必要となります。
- GitHubにGPG公開鍵を登録する
- commit時に署名するようgitの設定を変更する
具体的な作業コマンドを以下に示します。
# 公開鍵の出力
$ gpg --armor --export ABD16A9E824711BD1D3991EB49ABEB4CA549A419
# commit時に署名するようgitの設定を変更する
$ git config --global gpg.program $(which gpg)
$ git config --global user.signingKey ABD16A9E824711BD1D3991EB49ABEB4CA549A419
$ git config --global commit.gpgsign true
メールアドレスはGitHubで検証済みのものである必要があります。user-idのメールアドレスが一致しない場合には、複数user-idを登録するの手順で、GitHubで使用しているメールアドレスを追加します。
暗号化
GPGでは、公開鍵暗号方式と対称鍵暗号方式の両方をサポートしています。
公開鍵(非対称鍵)による暗号化
--encrypt
オプションを使用してデータを暗号化できます。受信者の公開鍵でデータを暗号化するため --recipient
オプションで受信者のuser-idを指定します。
$ gpg --encrypt --recipient Bob test.txt
$ gpg --decrypt test.txt.gpg
gpg: encrypted with cv25519 key, ID F17DBE6902AC1669, created 2024-08-16
"Bob <bob@example.com>"
This is a test document.
生成された暗号ファイルは、デフォルトで元ファイルの末尾に .gpg
が付加されます。復号するには --decrypt
オプションを使用します。
対称鍵による暗号化
公開鍵を使用せず一時的なパスフレーズで暗号化する方法もあります。この場合は --symmetric
オプションで暗号化します。
$ cat test.txt
This is a test document.
$ gpg --symmetric test.txt
実行時にパスフレーズを要求されるため、(GPG鍵のパスフレーズとは異なる)一時的なパスフレーズを指定します。このパスフレーズを暗号データの受信者と共有することになります。
$ ls test.txt*
test.txt test.txt.gpg
$ gpg --decrypt --output test.txt.decoded test.txt.gpg
gpg: AES256.CFB encrypted data
gpg: encrypted with 1 passphrase
$ cat test.txt.decoded
This is a test document.
生成された暗号ファイルは、デフォルトで元ファイルの末尾に .gpg
が付加されます。復号するには --decrypt
オプションを使用します。テキストファイルでない場合は --output
オプションで出力先ファイルパスを指定するとよいでしょう。
terraformでのIAMアクセスキー発行
terraform
の AWS Provider
ではIAMユーザの認証情報をPGP鍵で暗号化して生成できます。これにより、AWSの機密情報を安全に管理し、配布することが可能になります。ここではアクセスキー情報を暗号化して出力する方法を説明します。
まず、公開鍵情報を取得します。ASCII Armored形式(--armorオプション)ではなくバイナリ出力された鍵情報をBase64エンコードした文字列を使用します。IAMユーザの利用者に以下のようなコマンドで出力してもらいましょう。
$ gpg --export ABD16A9E824711BD1D3991EB49ABEB4CA549A419 | base64
取得した公開鍵の文字列を aws_iam_access_key
の pgp_key
に指定します。以下のterraformコードは、IAMユーザを作成し、そのユーザのアクセスキーを生成して暗号化します。
resource "aws_iam_user" "this" {
name = "alice"
}
resource "aws_iam_access_key" "this" {
user = aws_iam_user.this.name
pgp_key = "mDMEZr9i8RYJKwYBBAHaRw8BAQdAxXdjoE3lftnDHfyREJzlpodSn5/B9aGcWTpKoP9uFBq0GUFsaWNlIDxhbGljZUBleGFtcGxlLmNvbT6IkwQTFgoAOxYhBKvRap6CRxG9HTmR60mr60ylSaQZBQJmv2LxAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEEmr60ylSaQZLJYBAOJJUQfqyxX/3CR0eOs/bge1rf0ufC/qsZmCtl4gvOI8AQDlWvEkKFdQMTqzjl9RJoRbDgOpEo3gHCY5tvdI7eBFBrQVQm9iIDxiaWJAZXhhbXBsZS5jb20+iJMEExYKADsWIQSr0WqegkcRvR05ketJq+tMpUmkGQUCZsTMBgIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRBJq+tMpUmkGXY6AP474ZOfksqjEIc77G9DVeavjSY8aoborIgN8IjNZfSGwQD9EIcWaWXx8Xsc5oLpKMQLdd0mwAmafqKcbpdrSKCBjwG4OARmv2LxEgorBgEEAZdVAQUBAQdAK+WZM/Q3iy20KCqlRSGefFMTh58opKOKsl/91li1dGMDAQgHiHgEGBYKACAWIQSr0WqegkcRvR05ketJq+tMpUmkGQUCZr9i8QIbDAAKCRBJq+tMpUmkGYD0AQC1VFv0bhLBKQVvyK9YAjusaJUFY00naT12El2VW/0pFwD/aKeYO4c3KNZk4+Ir37QhbMUJ7KqJps3HyClVx6N1rga4MwRmv2r3FgkrBgEEAdpHDwEBB0DjdRq/m/PG7jkq7c7WeTG8C7MSoXqwCXjgk10XNzhGeYh4BBgWCgAgFiEEq9FqnoJHEb0dOZHrSavrTKVJpBkFAma/avcCGyAACgkQSavrTKVJpBnmwwEAnybhzym7o3ViE0h4kTLsiFCWodao41l3w1Ls66aL9NsA/2wBL7QE0MaWQNYyGfXroxBoKIZ1MuM1UDnbxCZ1RlAGuDMEZsNtCRYJKwYBBAHaRw8BAQdAyXPPydthvN6skA1XgNkoLWnUkhX9buWW04tKYxsMUFWI7wQYFgoAIBYhBKvRap6CRxG9HTmR60mr60ylSaQZBQJmw20JAhsCAIEJEEmr60ylSaQZdiAEGRYKAB0WIQTZ/yrwsATxrECrNTk9AzYGh4LrTAUCZsNtCQAKCRA9AzYGh4LrTDQdAP9L7A/6y2UhN5OQdJknhoygEnli20d8M9tc1YKNE3RxAQEAyRcLkr0NYTS3dg8G/dD2eChsXLGkOPpIKahp8F2qJgcxIwD+NjX7mXMCz0zPDTdKow4FRD77iDdPY1RVk2em2DaUBbsA/RwvAMDo63P9rk10nBlHaCNN5OG4VFDqPmUjV/abE08J"
}
output "access_key_id" {
value = aws_iam_access_key.this.id
}
output "secret_access_key" {
value = aws_iam_access_key.this.encrypted_secret
}
このコードをapplyすると、以下のようにIAMアクセスキーのIDと暗号化されたシークレットの文字列がそれぞれ出力されます。これらの情報をIAMユーザの利用者に送付しましょう。
$ terraform apply
...
Outputs:
access_key_id = "AAAAAAAAAAAAAAAAAAAAAAAAA"
secret_access_key = "XXXXXXXXXXXXXXXXXXXXXXXXX"
認証情報を受け取った利用者は、自分の持つ秘密鍵で暗号化された文字列を復号できます。
$ export AWS_ACCESS_KEY_ID="AAAAAAAAAAAAAAAAAAAAAAAAA"
$ export AWS_SECRET_ACCESS_KEY=$(echo "XXXXXXXXXXXXXXXXXXXXXXXXX" | base64 --decode | gpg --decrypt)
$ aws ec2 describe-instances
上記の例では、pgp_key
に直接公開鍵のBase64文字列を指定していますが、keybase:(user_id)
のように指定することでも keybase に登録された公開鍵を参照できます。GitHubのGPGキーを参照できてもよさそうですが、Pull Requestまでは出ているものの優先度が上がらず保留のままとなっているようです。
terraformでは、同様にaws_iam_user_login_profileを用いてログインパスワードを暗号化して設定できます。
認証
GPG鍵によるOpenSSH接続
GPGで作成した認証鍵はOpenSSHへの接続に使用できます。公開鍵はSSH公開鍵の出力の手順を参考に出力しているものとします。
まずは認証鍵の keygrip
を $GNUPGHOME/sshcontrol
に追記します。これには --with-keygrip
オプションを付けて鍵一覧を表示し、 [A]
(Authentication)の表示がある鍵の keygrip
文字列を使用します。
$ gpg --list-keys --with-keygrip
[keyboxd]
---------
pub rsa4096 2016-05-17 [SC]
0A9AF2115F4687BD29803A206B73A36E6026DFCA
Keygrip = DB892E9FBD75B31C678F5F3BEB633997B5F88206
uid [ full ] RabbitMQ Release Signing Key <info@rabbitmq.com>
sub rsa4096 2016-05-17 [E]
Keygrip = E795E0332C35471A689717719F032EC288FE818C
pub ed25519 2024-08-16 [SC]
ABD16A9E824711BD1D3991EB49ABEB4CA549A419
Keygrip = C082C125437D924F41FA5BDCAC6FC820622FCC9E
uid [ultimate] Bob <bob@example.com>
uid [ultimate] Alice <alice@example.com>
sub cv25519 2024-08-16 [E]
Keygrip = 42C8A11340799CF88F745B5FF443A0734A623829
sub ed25519 2024-08-16 [A]
Keygrip = EDAF4373719985F98C203FBA5AFEC6A055BE12EE
sub ed25519 2024-08-19 [S]
Keygrip = 1DF7AEDA7537399463FEF4A5EEF91FCCEF894750
$ echo EDAF4373719985F98C203FBA5AFEC6A055BE12EE >> $GNUPGHOME/sshcontrol
次に、 GPG Agent
のSSHサポートを有効化するため $GNUPGHOME/gpg-agent.conf
に enable-ssh-support
を追記して再起動します。
echo "enable-ssh-support" >> ~/.gnupg/gpg-agent.conf
gpgconf --reload gpg-agent
最後に SSHクライアントが GPG Agent
のソケット経由で通信するように、環境変数 SSH_AUTH_SOCK
に GPG Agent
のソケットを指定します。必要に応じて、この設定を永続化するために .bashrc
などに追記します。
$ export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
その他
トラブルシューティング
TerminalでEnter押下時に^Mと入力されてしまう問題の解決
ターミナル上で stty sane
コマンドを実行することで改善されることがあります。
stty
は標準入力デバイスに対するI/Oオプションを設定するコマンドで、sane
はターミナル設定を正常値に戻す指定です。GPGとは直接関係ありませんが、作業中に一度発生して困ったのでメモしておきます。(pinentryと関連していそうですが、以降再現がないので詳しくは未調査)
A locale function failed と出力されてエラー中断される
gpg: signing failed: A locale function failed
これも発生条件が定かではありませんが、 LANG
や LC_CTYPE
がCロケールである場合などにpinentry
がロケール関数をうまく呼べずに処理が中断されるようです。このときは LC_CTYPE="ja_JP.UTF-8"
など適切な設定を明示することで正常に動作します。
gpg: keyserver receive failed: Network is unreachable でキーサーバに繋がらない
GPG 2.1以降では、キーサーバへのアクセスは dirmngr
と呼ばれるデーモンが担当します。キーサーバに接続できない場合は、このデーモンが正常に動作していない可能性があります。
調べた限りではmacOSでの報告が多い事象のようですが、この問題に対しては dirmngr.conf
に standard-resolver
を指定することで解決します。standard-resolver
はシステムの標準DNSを使用するオプションですが、一部環境では組み込みDNSとの相性が悪いと考えられます。
$ cat $GNUPGHOME/dirmngr.conf
standard-resolver
$ pkill dirmngr
dirmngr
のmanによると standard-resolver
は主にデバッグ用途で使用するとの記載がありますが、上記の回避手順は Apache Pulsarのドキュメントなどにも記載がある、一般的な対処方法のようです。
参考資料リンク
- https://text.baldanders.info/openpgp/gnupg-cheat-sheet/
- https://blog.3qe.us/entry/2022/10/03/012420
- https://wiki.gentoo.org/wiki/GnuPG/ja
- https://wiki.archlinux.jp/index.php/GnuPG
Discussion