動的接続
暗号化されたJSON認証を使用して、Keeperコネクションマネージャーを外部データソースと連携
概要
Keeperコネクションマネージャーでは、暗号化されたJSONファイルを使用して、任意のカスタムソフトウェアまたはサードパーティ製アプリケーションと連携するように設定できます。このJSONファイルでユーザーを認証すると同時にリモート接続へのアクセスを許可します。
インストール
動的接続機能を使用するには、Keeperコネクションマネージャー用の暗号化JSON認証モジュールをインストールする必要があります。この機能を有効にするには、keeper/guacamoleイメージ内のDocker ComposeファイルのJSON_*
パラメータを更新します。
JSON_SECRET_KEY
JSON_TRUSTED_NETWORKS
これらのパラメータを有効にすると、Keeperコネクションマネージャーの認証拡張機能がロードされます。この拡張機能は、HMAC/SHA-256を使用して署名され、AES-128 CBCで暗号化されたJSONを使用してユーザーを認証します。このJSONには、認証しているユーザーを表す情報がすべて (アクセス可能なすべての接続を含む) 含まれているため、この拡張機能は、Keeperコネクションマネージャーを外部アプリケーションと連携する簡単な手段となります。
JSON_SECRET_KEY
は128ビットで、以下のように32桁の16進値で指定する必要があります。
4c0b569e4c96df157eee1b65dd0e4d41
この鍵は、ランダムなものであれば基本的に何でも構いません。このような鍵を生成する簡単な方法は、「md5sum」ユーティリティにパスフレーズをechoコマンドで入力することで、パスフレーズから128ビット鍵を生成するためにOpenSSL自体が使用している手法となります。以下に例を示します。
echo -n "SomeRandomizedPassword" | md5sum
4c0b569e4c96df157eee1b65dd0e4d41
以下はopensslを直接使用する例です。
echo -n "SomeRandomizedPassword" | openssl md5
暗号化されたJSONを既知のマシングループやプライベートサブネットからしか受信しない場合は、JSON_TRUSTED_NETWORKS
プロパティを使用して、受信したJSONの受け入れを信頼できるマシンのみにさらに制限することをお勧めします。このフィールドは、信頼できるIPアドレスやCIDRサブネットのコンマ区切りのリストです。以下はその例です。
127.0.0.0/8, 10.0.0.0/8
JSON形式
JSONの一般的な形式 (暗号化されて、署名され、Keeperコネクションマネージャーに送信される前) は以下のとおりです。
{
"username" : "arbitraryUsername",
"expires" :TIMESTAMP,
"connections" : {
"Connection Name" : {
"protocol" :"PROTOCOL",
"parameters" : {
"name1" : "value1",
"name2" : "value2",
...
}
},
...
}
}
例えば、craigとしてログインして、すぐにLinuxサーバーへのSSH接続を開始するJSONファイルが必要な場合、そのファイルは以下のようになります。
{
"username" : "craig",
"expires" : "1740860895000",
"connections" : {
"Kali Linux Server" : {
"protocol" : "ssh",
"parameters" : {
"hostname" : "192.168.1.2",
"port" : "22",
"username" : "kali",
"private-key":"<contents of PEM encoded SSH key>"
}
}
}
}
ここで「expires」は標準のUNIXエポックタイムスタンプでミリ秒単位 (1970年1月1日UTC真夜中からのミリ秒数) であり、PROTOCOL
はGuacamoleがサポートする任意のプロトコルの内部名で、vnc
、rdp
、ssh
などとなります。
以下は、現在から24時間後に期限切れになるタイムスタンプの例です。
echo $(($(date -v+24H +%s) * 1000))
サーバーの時刻がタイムスタンプの時刻を過ぎると、JSONは有効として受け入れられなくなります。タイムスタンプが指定されていない場合、データは失効しません。これは望ましいことですが、慎重に検討せずに指定を省くべきではありません。通常は、タイムスタンプを指定して、暗号化されたJSONの使用を適切な時間間隔に制限し、リプレイ攻撃を防ぐことが重要です。
Keeperコネクションマネージャーに送信する必要のある最上位のJSONオブジェクトには、以下のプロパティがあります。
username
string
JSONによって認証されたユーザーの一意のユーザー名。ユーザーが匿名の場合は、空の文字列 (""
) にする必要があります。
expires
number
署名が有効であっても、ミリ秒の解像度を持つ標準のUNIXエポックタイムスタンプ (UTCの1970年1月1日深夜からの経過ミリ秒数) として、JSONが受け入れられなくなる絶対時間。
connections
object
対応する一意の名前でユーザーに公開する必要がある接続のセット。ユーザーに公開される接続がない場合は、単に空のオブジェクト ({}
) で構いません。
送信された各JSONオブジェクト内で定義された各接続には、以下のプロパティがあります。
protocol
string
サポートされているプロトコルの内部名 (vnc
、rdp
、ssh
など)。
parameters
object
接続に適用する接続パラメータの名前と値のペアを表すオブジェクト (*)。
(*) プロパティの名前を確認するには、Keeperコネクションマネージャーの接続UIでフィールドを右クリックし、フィールドのDOM要素「name」を確認します。
暗号化されたJSONの生成
上記のJSON形式でユーザーを認証するには、Docker ComposeファイルのJSON_SECRET_KEY
値で指定された128ビットの同じ秘密鍵を使用して、JSONに署名と暗号化の両方を行う必要があります。
上記の形式でのJSONを生成します。
HMAC/SHA-256の秘密鍵 (
JSON_SECRET_KEY
プロパティに格納されているのと同じ128ビット鍵) を使用してJSONに署名します。署名されたプレーンテキストのJSONの先頭に署名プロセスのバイナリの結果を追加します。CBCモードでAESを使用し、初期ベクトル (IV) をすべて0バイトに設定して、手順2の結果を暗号化します。
暗号化された結果をbase 64でエンコードします。
暗号化された結果を、
data
という名前のHTTPパラメータの値として、/api/tokens
RESTエンドポイントにPOSTします (または、data
という名前のクエリパラメータとしてKeeperコネクションマネージャーページのURLに含めます)。
たとえば、Keeperがkcm.example.comで実行されており、BASE64_RESULT
が上記のプロセスの結果である場合、「curl」ユーティリティで実行すると、以下のようになります。
$ curl --data-urlencode "data=BASE64_RESULT" https://kcm.example.com/api/tokens
/api/tokens
にPOSTする前、またはURLに含める前に、必ずbase64でエンコードされた結果をURLエンコードしてください。Base64には、URL内で特別な意味を持つ「+」と「=」の両方の文字を使用できます。
データが何らかの形で無効である場合、署名が一致しない場合、復号化または署名の検証が失敗した場合、または送信されたデータの有効期限が切れている場合、RESTサービスは無効なクレデンシャルエラーを返し、ユーザーに説明を表示せずに失敗します。発生したエラーの詳細は、KCMのログに記録されます。
参照実装
Apache Guacamoleのソースコードには、doc/encrypt-json.sh
というシェルスクリプトが含まれており、OpenSSLコマンドラインユーティリティを使用して、guacamole-auth-json
が要求する形式でJSONを暗号化および署名します。このスクリプトは詳細なコメントが付いており、優れた参照実装として、テスト用、開発のための比較点として機能します。スクリプトを実行するには、以下のコマンドを使用します。
$ ./encrypt-json.sh HEX_ENCRYPTION_KEY file-to-sign-and-encrypt.json
以下はauth.json
というファイルに以下の内容が含まれている場合となります。
{
"username" : "test",
"expires" : "1446323765000",
"connections" : {
"My Connection" : {
"protocol" : "rdp",
"parameters" : {
"hostname" : "10.10.209.63",
"port" : "3389",
"ignore-cert": "true",
"recording-path": "/recordings",
"recording-name": "My-Connection-${GUAC_USERNAME}-${GUAC_DATE}-${GUAC_TIME}"
}
},
"My OTHER Connection" : {
"protocol" : "rdp",
"parameters" : {
"hostname" : "10.10.209.64",
"port" : "3389",
"ignore-cert": "true",
"recording-path": "/recordings",
"recording-name": "My-OTHER-Connection-${GUAC_USERNAME}-${GUAC_DATE}-${GUAC_TIME}"
}
}
}
}
以下を実行します。
$ ./encrypt-json.sh 4C0B569E4C96DF157EEE1B65DD0E4D41 auth.json
以下が出力されます。
A2Pf5Kpmm97I2DT1PifIrfU6q3yzoGcIbNXEd60WNangT8DAVjAl6luaqwhBJnCK
uqcf9ZZlRo3uDxTHvUM3eq1YvdghL0GbosOn8Mn38j2ydOMk+Cd15a8ggb4/ddt/
yIBK4DxrN7MNbouZ091KYtXC6m20E6sGzLy676BlMSg1cmsENRIihOynsSLSCvo0
diif6H7T+ZuIqF7B5SW+adGfMaHlfknlIvSpLGHhrIP4aMYE/ZU2vYNg8ez27sCS
wDBWu5lERtfCYFyU4ysjRU5Hyov+yKa+O7jcRYpw3N+fHbCg7/dxVNW07qNOKssv
pzUciGvDPUCPpa02WmPJNEBowwQireO1952/MNAI77cW2UepbljD/bwOiZl2THJz
LrENo7K5acimBa+EjWEesgn7lx/WTCF3zxR6TH1CWrQM8Et1aUK1Nf8K11xEQbTy
klyaNtCmTfyahRZ/fUPxDNrdJVpPOSELkf7RJO5tOdK/FFIFIbze3ZUyXgRq+pHY
owpgOmudDBTBlxhXiONdutRI/RZbFM/7GBMdmI8AR/401OCV3nsI4jLhukjMXH3V
f3pQg+xKMhi/QExHhDk8VTNYk7GurK4vgehn7HQ0oSGh8pGcmxB6W43cz+hyn6VQ
On6i90cSnIhRO8SysZt332LwJCDm7I+lBLaI8NVHU6bnAY1Axx5oH3YTKc4qzHls
HEAFYLkD6aHMvHkF3b798CMravjxiJV3m7hsXDbaFN6AFhn8GIkMRRrjuevfZ+q9
enWN14s24vt5OVg69DljzALobUNKUXFx69SR8EpSBvUcKq8s/OgbDpFvKbwsDY57
HGT4T0CuRIA0TGUI075uerKBNApVhuBA1BmWJIrI4JXw5MuX6pdBe+MYccO3vfo+
/frazj8rHdkDa/IbueMbvq+1ozV2+UuxrbaTrV2i4jSRgd74U0QzOh9e8Q0i7vOi
l3hnIfOfg+v1oULmZmJSeiAYWxeGvPptp+n7rNFqHGM=
結果として得られたbase64エンコードされたデータは、Keeperコネクションマネージャーのdata
パラメータを使用して送信することで、ユーザーを認証し、JSONに記載された接続へのアクセスを許可します。このアクセスはexpires
タイムスタンプに達するまで有効で、それ以降はJSONは受け入れられなくなります。
この暗号化されたBase64データを使用して、コネクションマネージャーを起動する方法は2つあります。
HTTP POST
HTTP POSTリクエストを生成する場合
curl --data-urlencode "data=BASE64_RESULT" https://kcm.example.com/api/tokens
Postmanでは、x-www-form-urlencoded
データを含むPOSTリクエストを使用してテストできます。
HTTP GET
HTTP GETリクエストを介してブラウザで接続を読み込むためのURLを生成する場合、改行を削除し、Base64ペイロードをURLエンコード文字列に変換します。以下のキー変換が必要となります。
+
→%2B
/
→%2F
=
→%3D
Pythonで変換することもできます。
python3 -c "import urllib.parse; print(urllib.parse.quote('XXXX', safe=''))"
その後、以下のようにURLエンコードされた文字列をサーバーのURL内のdata
パラメータとして指定します。
https://my.kcmserver.com/?data=URL_ENCODED_BASE64_STRING
これをブラウザで開くと、接続が即座に認証されて開きます。
Last updated