Open8

Vaultで発行した証明書を使ってElixirでmTLS通信する

栗林健太郎栗林健太郎

環境変数を設定する

export VAULT_ADDR=http://127.0.0.1:8200

Vaultを起動する

config/vault.hcl
disable_mlock = true

listener "tcp" {
  address = "0.0.0.0:8200"
  tls_disable = 1
}

backend "file" {
  path = "./secrets"
}

起動。

⟩ vault server -config=config/vault.hcl
==> Vault server configuration:

                     Cgo: disabled
              Go Version: go1.16.5
              Listener 1: tcp (addr: "0.0.0.0:8200", cluster address: "0.0.0.0:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
               Log Level: info
                   Mlock: supported: false, enabled: false
           Recovery Mode: false
                 Storage: file
                 Version: Vault v1.7.3
             Version Sha: 5d517c864c8f10385bf65627891bc7ef55f5e827+CHANGES

==> Vault server started! Log data will stream in below:

2021-07-25T01:58:06.686+0900 [INFO]  proxy environment: http_proxy="" https_proxy="" no_proxy=""
2021-07-25T01:58:06.686+0900 [WARN]  no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set
栗林健太郎栗林健太郎

初期化

⟩ vault operator init
Unseal Key 1: DmboreWfnSRaSgdgRtbETcuBNcm+wtm0AghBcHgv80GE
Unseal Key 2: QuiApVc8E0+Mm1pjoPk/7x8hSItPcO9gq6Em7rBZ5amh
Unseal Key 3: ZWn3AmlzIlCtY4DCUiJgRnBaE9b+LSgSgMZN2hurpt1+
Unseal Key 4: 6VqXXpObhHtt1+t6r3nuQQaQot/FLz+l0XBbRPX9Y9eV
Unseal Key 5: AQdPtu6X0r0hLTyR4XD4EwbB69EgyMaWQ6Az3CFnuzYE

Initial Root Token: s.MgHttus5Aq8UJCoamApicWLZ

Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.

Vault does not store the generated master key. Without at least 3 key to
reconstruct the master key, Vault will remain permanently sealed!

It is possible to generate new unseal keys, provided you have a quorum of
existing unseal keys shares. See "vault operator rekey" for more information.

生成されたキーのうち3つがあれば、unsealできる(もちろん厳重に管理しておく必要あり)。上から3つを使ってunsealする。

⟩ vault operator unseal DmboreWfnSRaSgdgRtbETcuBNcm+wtm0AghBcHgv80GE
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    1/3
Unseal Nonce       b1b8f825-97e6-7ca7-b1d7-6bd82ce290a7
Version            1.7.3
Storage Type       file
HA Enabled         false

~/src/github.com/kentaro/elixir_mtls_example · (main±)
⟩ vault operator unseal QuiApVc8E0+Mm1pjoPk/7x8hSItPcO9gq6Em7rBZ5amh
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    2/3
Unseal Nonce       b1b8f825-97e6-7ca7-b1d7-6bd82ce290a7
Version            1.7.3
Storage Type       file
HA Enabled         false

~/src/github.com/kentaro/elixir_mtls_example · (main±)
⟩ vault operator unseal ZWn3AmlzIlCtY4DCUiJgRnBaE9b+LSgSgMZN2hurpt1+
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         1.7.3
Storage Type    file
Cluster Name    vault-cluster-02ae66b2
Cluster ID      b7d3c24a-7948-1064-0ad6-27143706e4b4
HA Enabled      false

ログインする。トークンは、上記の vault operator init の結果に書かれている。

⟩ vault login
Token (will be hidden):
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                s.MgHttus5Aq8UJCoamApicWLZ
token_accessor       r7nR3Zr8TViivQUq5acEt2Sk
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]
栗林健太郎栗林健太郎

Root CAの作成

secrets enable - Command | Vault by HashiCorpを使う。

⟩ vault secrets enable -path=elixir_mtls_example -description="Root CA for Elixir mTLS Example" pki
Success! Enabled the pki secrets engine at: elixir_mtls_example/

ルートCAなので長めがいいよねということで、最大で設定可能なTTLを87,600時間(10年間)にする。

⟩ vault secrets tune -max-lease-ttl=87600h elixir_mtls_example
Success! Tuned the secrets engine at: elixir_mtls_example/

これでsecretができた。

⟩ vault secrets list
Path                    Type         Accessor              Description
----                    ----         --------              -----------
cubbyhole/              cubbyhole    cubbyhole_9e57091e    per-token private secret storage
elixir_mtls_example/    pki          pki_9410f901          Root CA for Elixir mTLS Example
identity/               identity     identity_5e242c96     identity store
sys/                    system       system_4e6aad98       system endpoints used for control, policy and debugging

Root CAを作る(Generate Root API)。

⟩ vault write elixir_mtls_example/root/generate/internal common_name="Root CA for Elixir mTLS Example" ttl=87600h key_bites=4096 exclude_cn_from_sans=true
Key              Value
---              -----
certificate      -----BEGIN CERTIFICATE-----
MIIDRTCCAi2gAwIBAgIUGtBOf5EICra0fX36EeOxJYfzYhYwDQYJKoZIhvcNAQEL
BQAwKjEoMCYGA1UEAxMfUm9vdCBDQSBmb3IgRWxpeGlyIG1UTFMgRXhhbXBsZTAe
Fw0yMTA3MjQxNzMzMjJaFw0zMTA3MjIxNzMzNTJaMCoxKDAmBgNVBAMTH1Jvb3Qg
Q0EgZm9yIEVsaXhpciBtVExTIEV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCckr7jj8Ed88AhMWNlU1MSKo/BHj212ovdOnuJpjPHwKz/6Zg5
JnTjzFFY7gk2HbA6WxEQ2Modc/Z1VhXt2/LsP5CyhxitfQCmXdAeIuBOO9Y3K50e
n/pU2WKhNfxp6YWuEmX8A8d3IwCGlUgb+q2qOmxSG/j7VrD370EZ//xpwWrdfBpg
aQ/T36RFK21hRe3FgVxoZCNrHNPB43ID1q7TU5IogNCb+qfxixul+7xniTHjAhnq
x9kmL/3hsdrJh6Q841LshYh9i7OnyFMSW5mj9e1UxM2Udsq5UVK2qTe+DrT0fOGO
VM728dqWMsoR79k7ggiVPAXGnMy3RsLdU9f9AgMBAAGjYzBhMA4GA1UdDwEB/wQE
AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTKLWViwKu0aL6Cjs1ACh5t
0kBxYzAfBgNVHSMEGDAWgBTKLWViwKu0aL6Cjs1ACh5t0kBxYzANBgkqhkiG9w0B
AQsFAAOCAQEAKeAJEKTphsufTC/buJNY4NaN0bgetXW1UM5cihCdZkVoAEJeJ8pz
hqRPsNwVNFc1meUuc7lzNuhXYSqnPC1MCSNWbiq89ArJCaa/eJf+ZKzLCfG5R5ZU
6sFWLOkrWlXzxz9qRtZwGeXcPiPeaEqy04zvMOeotadTjd+uIAX4loY8sOIzNHjO
NtcwCu2sl4ungO8fbO4Ua4Yo5i5AdSxFOa7OwB99gQo0xodyWUFSA40sE542VsVn
NVMtIHmn7qqFyNHy/pMpp6HS9mYAAFSNjdAJHG78LDyA1PyoGxfRCh2YFoBdlngc
jR3M9/AlQjoEQpuFkglgf5H3II7wvHuzRQ==
-----END CERTIFICATE-----
expiration       1942508032
issuing_ca       -----BEGIN CERTIFICATE-----
MIIDRTCCAi2gAwIBAgIUGtBOf5EICra0fX36EeOxJYfzYhYwDQYJKoZIhvcNAQEL
BQAwKjEoMCYGA1UEAxMfUm9vdCBDQSBmb3IgRWxpeGlyIG1UTFMgRXhhbXBsZTAe
Fw0yMTA3MjQxNzMzMjJaFw0zMTA3MjIxNzMzNTJaMCoxKDAmBgNVBAMTH1Jvb3Qg
Q0EgZm9yIEVsaXhpciBtVExTIEV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCckr7jj8Ed88AhMWNlU1MSKo/BHj212ovdOnuJpjPHwKz/6Zg5
JnTjzFFY7gk2HbA6WxEQ2Modc/Z1VhXt2/LsP5CyhxitfQCmXdAeIuBOO9Y3K50e
n/pU2WKhNfxp6YWuEmX8A8d3IwCGlUgb+q2qOmxSG/j7VrD370EZ//xpwWrdfBpg
aQ/T36RFK21hRe3FgVxoZCNrHNPB43ID1q7TU5IogNCb+qfxixul+7xniTHjAhnq
x9kmL/3hsdrJh6Q841LshYh9i7OnyFMSW5mj9e1UxM2Udsq5UVK2qTe+DrT0fOGO
VM728dqWMsoR79k7ggiVPAXGnMy3RsLdU9f9AgMBAAGjYzBhMA4GA1UdDwEB/wQE
AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTKLWViwKu0aL6Cjs1ACh5t
0kBxYzAfBgNVHSMEGDAWgBTKLWViwKu0aL6Cjs1ACh5t0kBxYzANBgkqhkiG9w0B
AQsFAAOCAQEAKeAJEKTphsufTC/buJNY4NaN0bgetXW1UM5cihCdZkVoAEJeJ8pz
hqRPsNwVNFc1meUuc7lzNuhXYSqnPC1MCSNWbiq89ArJCaa/eJf+ZKzLCfG5R5ZU
6sFWLOkrWlXzxz9qRtZwGeXcPiPeaEqy04zvMOeotadTjd+uIAX4loY8sOIzNHjO
NtcwCu2sl4ungO8fbO4Ua4Yo5i5AdSxFOa7OwB99gQo0xodyWUFSA40sE542VsVn
NVMtIHmn7qqFyNHy/pMpp6HS9mYAAFSNjdAJHG78LDyA1PyoGxfRCh2YFoBdlngc
jR3M9/AlQjoEQpuFkglgf5H3II7wvHuzRQ==
-----END CERTIFICATE-----
serial_number    1a:d0:4e:7f:91:08:0a:b6:b4:7d:7d:fa:11:e3:b1:25:87:f3:62:16

このcertificateの部分をcerts/ca.crtとして保存しておく。

栗林健太郎栗林健太郎

サーバ証明書を作成する

まずはロールを作る。

⟩ vault write elixir_mtls_example/roles/localhost key_bites=2048 max_ttl=8760h allow_any_name=true
Success! Data written to: elixir_mtls_example/roles/localhost

証明書を作成する。

⟩ vault write elixir_mtls_example/issue/localhost common_name="localhost" ip_sans="127.0.0.1" ttl=720h foramt=pem
Key                 Value
---                 -----
certificate         -----BEGIN CERTIFICATE-----
MIIDWzCCAkOgAwIBAgIUb24LnYbGT6abqqpbuVdgAcGEAHswDQYJKoZIhvcNAQEL
BQAwKjEoMCYGA1UEAxMfUm9vdCBDQSBmb3IgRWxpeGlyIG1UTFMgRXhhbXBsZTAe
Fw0yMTA3MjQxNzQ2MTNaFw0yMTA4MjMxNzQ2NDNaMBQxEjAQBgNVBAMTCWxvY2Fs
aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRPk6Kj4HpfsBLP
6htjMPvlDvqApaCBSuwJiILI0cYZrf1fqT2iCBdXeOBk9IvdA4s61DTXnDBOPDsi
fEx2p8EJq8hsM27CusEmXl2RNhcimSP14RIU4KbPgupULVSpg/LMIElLSwDCtkWc
MDJ4YTd6Qq/1SwU1jjJB7hTlrfH6c7qr4xTWktTk+gJ5cnjomiee39i7Pqhz2Mc1
RjcYkkmAYWJpqoKvwnjN9QwlNF2pekaeVb+3dcZWJ5zD4i9PRm3HKag+aqH93Z41
3HAQ4Lx8irTpqsp33VXvuSarb+85tpb8iOiskwKotVA1YINw0qtwUpVatHVaaYQP
Rzb7XX8CAwEAAaOBjjCBizAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYB
BQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSnT1bH6mMS7AOCORIYfF4RocjDLDAf
BgNVHSMEGDAWgBTKLWViwKu0aL6Cjs1ACh5t0kBxYzAaBgNVHREEEzARgglsb2Nh
bGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBACoDuqj6RmL9/PturENR//Pi
QFKYhCIh2XA5YHd1lEIxY4PGmI8tZggjfqgpqzXgYTM6tKlidp1XqblqavC2cT+q
4768hVGHXfspxYimSlicXY+fPVbhkBxZmXhOg6etjaWg5WqeICSleEBu5yamfa7B
L8eHpgoHe8tKeDg3Ry8tUKZMd9OUb9i4V+zX8fxmwjJ8UezETQlHoCSyFcEardl+
IfF+2u+W5xw+XTr3F9fNdeEfI6K6CMuCY5a3ZzHVc87cnFCfdFbYLDn7jkwLG5kj
/+uAF1c81JP/KCDoAKAg8sYb1xofJrQho50MyQ2C3jS2q1neDoIqw1+Rs7cPUjM=
-----END CERTIFICATE-----
expiration          1629740803
issuing_ca          -----BEGIN CERTIFICATE-----
MIIDRTCCAi2gAwIBAgIUGtBOf5EICra0fX36EeOxJYfzYhYwDQYJKoZIhvcNAQEL
BQAwKjEoMCYGA1UEAxMfUm9vdCBDQSBmb3IgRWxpeGlyIG1UTFMgRXhhbXBsZTAe
Fw0yMTA3MjQxNzMzMjJaFw0zMTA3MjIxNzMzNTJaMCoxKDAmBgNVBAMTH1Jvb3Qg
Q0EgZm9yIEVsaXhpciBtVExTIEV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCckr7jj8Ed88AhMWNlU1MSKo/BHj212ovdOnuJpjPHwKz/6Zg5
JnTjzFFY7gk2HbA6WxEQ2Modc/Z1VhXt2/LsP5CyhxitfQCmXdAeIuBOO9Y3K50e
n/pU2WKhNfxp6YWuEmX8A8d3IwCGlUgb+q2qOmxSG/j7VrD370EZ//xpwWrdfBpg
aQ/T36RFK21hRe3FgVxoZCNrHNPB43ID1q7TU5IogNCb+qfxixul+7xniTHjAhnq
x9kmL/3hsdrJh6Q841LshYh9i7OnyFMSW5mj9e1UxM2Udsq5UVK2qTe+DrT0fOGO
VM728dqWMsoR79k7ggiVPAXGnMy3RsLdU9f9AgMBAAGjYzBhMA4GA1UdDwEB/wQE
AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTKLWViwKu0aL6Cjs1ACh5t
0kBxYzAfBgNVHSMEGDAWgBTKLWViwKu0aL6Cjs1ACh5t0kBxYzANBgkqhkiG9w0B
AQsFAAOCAQEAKeAJEKTphsufTC/buJNY4NaN0bgetXW1UM5cihCdZkVoAEJeJ8pz
hqRPsNwVNFc1meUuc7lzNuhXYSqnPC1MCSNWbiq89ArJCaa/eJf+ZKzLCfG5R5ZU
6sFWLOkrWlXzxz9qRtZwGeXcPiPeaEqy04zvMOeotadTjd+uIAX4loY8sOIzNHjO
NtcwCu2sl4ungO8fbO4Ua4Yo5i5AdSxFOa7OwB99gQo0xodyWUFSA40sE542VsVn
NVMtIHmn7qqFyNHy/pMpp6HS9mYAAFSNjdAJHG78LDyA1PyoGxfRCh2YFoBdlngc
jR3M9/AlQjoEQpuFkglgf5H3II7wvHuzRQ==
-----END CERTIFICATE-----
private_key         -----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAxE+ToqPgel+wEs/qG2Mw++UO+oCloIFK7AmIgsjRxhmt/V+p
PaIIF1d44GT0i90DizrUNNecME48OyJ8THanwQmryGwzbsK6wSZeXZE2FyKZI/Xh
EhTgps+C6lQtVKmD8swgSUtLAMK2RZwwMnhhN3pCr/VLBTWOMkHuFOWt8fpzuqvj
FNaS1OT6AnlyeOiaJ57f2Ls+qHPYxzVGNxiSSYBhYmmqgq/CeM31DCU0Xal6Rp5V
v7d1xlYnnMPiL09GbccpqD5qof3dnjXccBDgvHyKtOmqynfdVe+5Jqtv7zm2lvyI
6KyTAqi1UDVgg3DSq3BSlVq0dVpphA9HNvtdfwIDAQABAoIBAQCgOl9C6UUIPN+m
iyMGVZCemJgAKE6HUeBIBYPxU128tisH2jN1hbHa819Kr7vWCH+i/VJFCxKFbuXE
UmJnupUzfuRCAuZ76d6qVdnBvwsKGQgrjL22l2nBXS/6eNhC+NUksC1OBXFjXomN
CW1hVFXtBRI3MhuYVd0I8j0Tu1+dVyDIJsjFvKW2C7baoaeXQTJ2oraK5D2XWaQ/
I3gwHKikN1pT/3S4q4fmVdVYhfIRTZOFzX0Ils6FAT1ro+vcQ32Ytt+Hah70bQnF
ywUAP7FjG6QxFmNUnImaDk9TLWfSNWBHMNmPAfLlmD/tH+PBhJ0vbkYrD0JIFpYe
lKUtl7hZAoGBAMaXaTkl+e7hzWtxbu74Ry+oziiz9E/lvAKciUYk7OiCSvEMRSL8
qXsTfUt0U8/qlBMNe4oRgfc55PEzk8FRKo0zMqFOXrin5xbfd+r9FoyciHGbYoqe
/7cs1oWdVTzGbJ+JIPLOqcq6Q7Ul5ZYhuvG264OLFkt55JqN7E81zi7zAoGBAP0P
ZEGNFvalUeRigrWTx5z8phsqQgb5ZTX2Gv4ALmgbd+5LLK+SKQV9jUqKHpNlxp6O
LjJBWwPPwaMB2aov83zEp5HPssh0FJLrftaA5YV/ImeONEGzEUfsAK+1NbzHRPHR
RyAo5bCK2Gsle8+3SNWi6vW7bE2mCv31LjixnfJFAoGBAJqyGWJOBdoihOzcKMj4
GCO1ABrOy1Jtp731CC3e17jqvcv1femaHb9k2CYt0JfWqFALIZ/UsYPO0ltdjQx6
2IWzSw5CSSDYkffMTdJ8IdOYn+S3YNSQtKuQvu7INzynaLgBjuv1NmhYHiP/CE+h
qMlfbyhB8TUMF5qZUWoGhL0nAoGAQPKWVIyVfC/p2Ke/zEJlVNEzAH3T/F49r5++
RbpeLrH+EdaRXW4xwQr8HElel43jcAYlrRhA97V2iROMfbVY1IjUSQP5aqEANsTi
BMOIJL8AYXuJxeLjaIYVlwL3C8BI3ZdMneBhMvIvoTA5mpH7y3jIvNChdzxKTeuD
NWHAm9ECgYBVTLo9//T6vu4Njvx18hOOlWi0ee2mMp/1BhdH1TnPfZTnTtKLhzFW
5zy2HpobCLt3rJSgnrbtflEXKOkUR+X2N6ElMz4XyRPozXCswqaa5i1ddM5vdWlZ
IWTCrt8/bP4TKSebo7CR3Hi6qFtTDfwad+HmW9DhjnYjEv36Y+41dg==
-----END RSA PRIVATE KEY-----
private_key_type    rsa
serial_number       6f:6e:0b:9d:86:c6:4f:a6:9b:aa:aa:5b:b9:57:60:01:c1:84:00:7b

上記のcertificateprivate_keyとを、それぞれcerts/localhost.crtcerts/localhost.keyとして保存する。

栗林健太郎栗林健太郎

クライアント証明書を作成

クライアント証明書用のロールを作る(ノード間通信をする2つのノード分)。

⟩ vault write elixir_mtls_example/roles/client001 key_bites=2048 max_ttl=8760h allow_any_name=true
Success! Data written to: elixir_mtls_example/roles/client001

⟩ vault write elixir_mtls_example/roles/client002 key_bites=2048 max_ttl=8760h allow_any_name=true
Success! Data written to: elixir_mtls_example/roles/client002

んでもって証明書作成。

⟩ vault write elixir_mtls_example/issue/client001 common_name="localhost" ip_sans="127.0.0.1" ttl=720h foramt=pem

⟩ vault write elixir_mtls_example/issue/client002 common_name="localhost" ip_sans="127.0.0.1" ttl=720h foramt=pem

サーバの時と同じように、certificateとprivate keyをそれぞれファイルに保存する(certs/client{001,002}.{crt,key}に保存した)。

栗林健太郎栗林健太郎

TCPで接続を試みる

まずは、接続がちゃんと失敗するかどうかを確かめる。

一方はデフォルトの設定で起動する。

⟩ iex --sname node001@localhost -S mix

もう一方は、以下の設定ファイルを読み込ませて、TLS接続とクライアント認証を求める設定で起動する。

config/node002.ssl.conf
[
  {server,
    [{cacertfile, "certs/ca.crt"},
     {certfile, "certs/localhost.crt"},
     {keyfile, "certs/localhost.key"},
     {secure_renegotiate, true},
     {fail_if_no_peer_cert, true},
     {verify, verify_peer}     
    ]}
].
⟩ iex --sname node002@localhost --erl "-proto_dist inet_tls" --erl "-ssl_dist_optfile config/node002.ssl.conf" -S mix

node001の方からnode002に繋げようとすると

iex(node001@localhost)1> Node.connect(:node002@localhost)
false

繋がらない。node002の方では以下の通りエラーメッセージが表示される。

18:06:23.123 [info]  TLS :server: In state :hello at tls_record.erl:558 generated SERVER ALERT: Fatal - Unexpected Message
 - {:unsupported_record_type, 0}

クライアント証明書を送らない

今度は、TLSで接続を試みるが、サーバはクライアント認証を求めているにもかかわらずクライアント証明書を送らないことで、認証を失敗させてみる。

2つノードを立てるので、それぞれに設定ファイルを用意する。以下の設定では、クライアント認証を必要とするにもかかわらず、クライアントの設定を記述していない(つまり、TLSのセッション確立時にクライアント証明書を送らない)。

config/node001.ssl.conf
[
  {server,
    [{cacertfile, "certs/ca.crt"},
     {certfile, "certs/localhost.crt"},
     {keyfile, "certs/localhost.key"},
     {secure_renegotiate, true},
     {fail_if_no_peer_cert, true},
     {verify, verify_peer}     
    ]}
].
config/node002.ssl.conf
[
  {server,
    [{cacertfile, "certs/ca.crt"},
     {certfile, "certs/localhost.crt"},
     {keyfile, "certs/localhost.key"},
     {secure_renegotiate, true},
     {fail_if_no_peer_cert, true},
     {verify, verify_peer}     
    ]}
].

ターミナルを2つ立ち上げて、それぞれでノードを起動。

1つ目:

⟩ iex --sname node001@localhost --erl "-proto_dist inet_tls" --erl "-ssl_dist_optfile config/node001.ssl.conf" -S mix

2つ目:

⟩ iex --sname node002@localhost --erl "-proto_dist inet_tls" --erl "-ssl_dist_optfile config/node002.ssl.conf" -S mix

Node.connectを試みるとエラーになる。想定通り。

iex(node001@localhost)1> Node.connect(:node002@localhost)

03:29:15.682 [warn]  Description: 'Authenticity is not established by certificate path validation'
     Reason: 'Option {verify, verify_peer} and cacertfile/cacerts is missing'


03:29:15.784 [info]  TLS :client: In state :cipher received SERVER ALERT: Fatal - Handshake Failure

false
栗林健太郎栗林健太郎

mTLSしてみる

今度はクライアント側の設定もきちんとかいた。

config/node001.ssl.conf
[
  {server,
    [{cacertfile, "certs/ca.crt"},
     {certfile, "certs/localhost.crt"},
     {keyfile, "certs/localhost.key"},
     {secure_renegotiate, true},
     {fail_if_no_peer_cert, true},
     {verify, verify_peer}     
    ]},
  {client,
    [{cacertfile, "certs/ca.crt"},
     {certfile, "certs/client001.crt"},
     {keyfile, "certs/client001.key"},
     {secure_renegotiate, true},
     {fail_if_no_peer_cert, true},
     {verify, verify_peer}     
    ]}
].

config/node002.ssl.conf
[
  {server,
    [{cacertfile, "certs/ca.crt"},
     {certfile, "certs/localhost.crt"},
     {keyfile, "certs/localhost.key"},
     {secure_renegotiate, true},
     {fail_if_no_peer_cert, true},
     {verify, verify_peer}     
    ]},
  {client,
    [{cacertfile, "certs/ca.crt"},
     {certfile, "certs/client002.crt"},
     {keyfile, "certs/client002.key"},
     {secure_renegotiate, true},
     {fail_if_no_peer_cert, true},
     {verify, verify_peer}     
    ]}
].

先ほどと同じように、ターミナルを2つ立ち上げて、それぞれでノードを起動。

1つ目:

⟩ iex --sname node001@localhost --erl "-proto_dist inet_tls" --erl "-ssl_dist_optfile config/node001.ssl.conf" -S mix

2つ目:

⟩ iex --sname node002@localhost --erl "-proto_dist inet_tls" --erl "-ssl_dist_optfile config/node002.ssl.conf" -S mix

Node.connectしてみる。

iex(node001@localhost)1> Node.connect(:node002@localhost)
true

今度はうまくいった。