VyOS 1.4のAPIを利用できるようにする

VyOSにLet’s Encryptで取得したサーバ証明書をインストールしたい、でもVyOS上のcertbotではなく、別のLinux上で用意しているcertbotで取得したサーバ証明書を使いたい、というモチベーションからVyOSでAPIを使えるようにしました。
別にこのようなモチベーションじゃなく、単純にVyOSの設定を自動化するためにAPIを使いたいという場合にも参考になると思いますので、記事にしておきます。

環境

  • VyOS 1.4-rolling-202302080317
  • rolling releaseなので仕様が変更になったり、バグが含まれる可能性があります。(実際バグを踏んで酷い目に遭いました…)

サーバ証明書をインストールする

APIを使うためにHTTPSでアクセスするので、サーバ証明書のインストールが必要です。
基本的には、公式ドキュメントの通りで問題なく対応できます。

証明書と秘密鍵の下処理

証明書や秘密鍵は以下のようなフォーマットになっています。

-----BEGIN CERTIFICATE-----
...
certificate
...
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
...
private key
...
-----END PRIVATE KEY-----

VyOSへインストールする際は、以下の前処理をした上で設定する必要があります。

  • BEGIN、END行を削除
  • 改行を削除

これを行うために公式ドキュメントで紹介されている以下のコマンドを使って整形することにします。
証明書が置かれているLinux上でやっても、VyOSまで証明書を持ってきてVyOS上でやっても問題ありません。

tail -n +2 <証明書、秘密鍵のファイルパス> | head -n -1 | tr -d '\n'

このコマンドで出力された長い文字列を、以降の作業で使う事になります。
たとえば、後述の作業で使うLet’s Encryptの中間証明書を処理すると、以下のような結果になります。

[vyos@vyos ~]$ cat lets-encrypt-r3.pem
-----BEGIN CERTIFICATE-----
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
nLRbwHOoq7hHwg==
-----END CERTIFICATE-----
[vyos@vyos ~]$ tail -n +2 lets-encrypt-r3.pem | head -n -1 | tr -d '\n'
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAwWhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cPR5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdxsxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8ZutmNHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxgZ3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6WPTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wlikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQzCkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BImlJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1OyK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90IdshCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6ZvMldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqXnLRbwHOoq7hHwg==[vyos@vyos ~]$
33行目、出力の末尾に改行がないため、プロンプトが続いて表示される事に注意してください。

サーバ証明書・秘密鍵のインストール

冒頭に記載の通り、別途取得済みのサーバ証明書を導入します。
どうやらVyOSにはcertbotが入っていて単独で証明書を作ることも出来るらしい?あと自己署名証明書も作れるようですが、今回それらは使いません。

$ configure
# set pki certificate <証明書名> certificate <整形済みのサーバ証明書>
# set pki certificate <証明書名> private key <整形済みの秘密鍵>
このとき、現時点のバージョンでは、証明書名にダブルクォーテーションで囲って空白を含めると、save時にダブルクォーテーションが外れコンフィグが壊れます。
この状態でVyOSを再起動すると、壊れたコンフィグをロードできず、ゼロコンフィグ状態になるのでご注意ください。

CA証明書のインストール

LinuxのhttpdなどではCA証明書をインストールしなくても使えたりするのですが、VyOSでは導入必須のようです。
今回は自己署名証明書ではないので、CAの秘密鍵は不要で証明書だけインストールします。

今回はLet’s Encryptの証明書なので、Let’s Encryptのサイト上で公開されている証明書をダウンロードします。

Intermediate Certificates(中間証明書)と書かれているところにある、「Let’s Encrypt R3」の「Signed by ISRG Root X1」のpemファイルをダウンロードします。

この証明書も同様に整形をした上でインストールします。
これらの作業が全て終わればいったんコミットして保存しておきます。

# set pki ca LetsEncryptR3 certificate <整形済みのCA証明書>
# commit
# save

証明書名にLetsEncryptR3と設定していますが、お好みで変えてもらって問題ありません。

証明書の一覧を表示

オペレーションモードのshow pki certificateで正しく証明書が導入できているか確認しておきます。

# run show pki certificate
Certificates:
Name         Type    Subject CN        Issuer CN    Issued               Expiry               Revoked    Private Key    CA Present
-----------  ------  ----------------  -----------  -------------------  -------------------  ---------  -------------  -------------------
<cert name>  Server  CN=<common name>  CN=R3        2023-02-11 09:00:42  2023-05-12 09:00:41  No         Yes            Yes (LetsEncryptR3)

APIを有効にする

APIを使えるように、httpsサービスの設定をしていきます。

API用のキーを生成

API用のキーは何でも良いと思いますが、今回はUUIDを使うことにします。
以下は実行例ですので、参考にする場合はお手元で実行してください。

# uuidgen
414e8804-2494-4dcd-bad1-534a30db272d

HTTPS VirtualHostの設定

今回は一つだけ、default VitualHostを作成します。(defaultの名称は何でも構いません。)
ここで設定するlisten-portは、APIを実行するクライアントが接続するHTTPSのポート番号になります。

コンフィグモードで引き続き作業します。

# set service https certificates ca-certificate LetsEncryptR3
# set service https certificates certificate <証明書名>
# set service https virtual-host default listen-address <待ち受けIPアドレス>
# set service https virtual-host default listen-port <待ち受けポート>
# set service https virtual-host default server-name <VyOSのFQDN>

APIを有効化

APIキーは上記で生成したUUIDを指定します。
繰り返しますが、実行例ですので、参考にする場合はお手元で生成したものをご利用ください。

api-restrictは、指定したVirtual HostでのみAPIの実行を許可する設定です。
今回はdefaultしか作成していないので関係ありませんが、一応設定しておきます。

設定したらコミットして保存し、オペレーションモードに戻ります。

# set service https api keys id <APIキー名> key '414e8804-2494-4dcd-bad1-534a30db272d'
# set service https api-restrict virtual-host 'default'
# commit
# save
# exit

今回設定しませんが、set service https api portでAPIの待ち受けポートを設定することができます。
これは内部で利用するポートなので、APIを実行するクライアントが接続するポートではありません。
デフォルトは8080/tcpなので、他で設定しているポートと重複する場合は変更してください。

HTTPS/APIの起動を確認する

ぱっと見では、httpsサービスの動作状況を確認するshowコマンドが無さそうなので、ポートが待ち受けられていることを確認します。

$ ss -nlt
State   Recv-Q  Send-Q    Local Address:Port     Peer Address:Port  Process
...(snip)...
LISTEN  0       2048          127.0.0.1:8080          0.0.0.0:*
LISTEN  0       511       <listen-addr>:<port>        0.0.0.0:*
...(snip)...

出力は省略していますが、HTTPSのlisten-addresslisten-portでポートが待ち受けられており、127.0.0.1:8080でAPIのポートが待ち受けられていることが見て取れます。

クライアントからAPIにアクセスする

外部のクライアントからHTTPSアクセスも試してみます。

ブラウザから https://<VyOSのFQDN>:<待ち受けポート> へアクセスすると、nginxのデフォルトページが表示されます。
証明書に問題がなければ特に証明書エラーなども表示されません。

外部のクライアント(Linux)からcurlでAPIの実行も試してみます。
keyには事前に生成、設定したAPIキーを入力します。

$ curl --location --request POST 'https://<VyOSのFQDN>:<待ち受けポート>/retrieve' --form data='{"op": "showConfig", "path": []}' --form key='414e8804-2494-4dcd-bad1-534a30db272d'

問題がなければコンフィグがだだーっと表示されるはずです。

サーバ証明書をAPIで更新する

APIが使えるようになったのは良いのですが、Let’s Encryptは3ヶ月に1度証明書を更新することになります。
証明書を更新したら、API経由で新しい証明書をインストールするようにスクリプトを作っておきます。

上でしれっとコンフィグ取得をしてしまっていますが、APIの使い方については詳しくはドキュメントを参照してください。

APIでコンフィグを設定

APIでコンフィグ設定すると、自動でcommitされてしまいます。
サーバ証明書は秘密鍵とセットで更新しなければなりませんので、certificateprivate keyの両方の設定を同時に行います。

手作業でcurlを実行する場合は、以下のコマンドになります。
忘れた頃だと思うので再度繰り返しますが、実行例ですので、APIキーはお手元で生成したものをご利用ください。

$ curl --location --request POST 'https://<VyOSのFQDN>:<待ち受けポート>/configure' --form data='[{"op": "set", "path": ["pki", "certificate", "<証明書名>", "certificate", "<整形済みのサーバ証明書>"]}, {"op": "set", "path": ["pki", "certificate", "<証明書名>", "private", "key", "<整形済みの秘密鍵>"]}]' --form key='414e8804-2494-4dcd-bad1-534a30db272d'
これを実行することでサーバ証明書が設定済みのものから変更された場合、curlは正常終了せずコネクションが切断されてしまいます。
証明書が変更されてhttpsサービスが再起動することによるものなので正常な動作です。

APIでコンフィグを保存

APIでコンフィグを設定するとcommitはされますが、saveはされません。
後追いでコンフィグ保存のAPIも実行します。

$ curl --location --request POST 'https://<VyOSのFQDN>:<待ち受けポート>/config-file' --form data='{"op": "save"}' --form key='414e8804-2494-4dcd-bad1-534a30db272d'

スクリプト化する

上記を手作業で定期実行するのは当然辛いので、スクリプトを作ってcronなどに登録しておきましょう。
スクリプトにする際、変数展開を考慮してシングルクォーテーションとダブルクォーテーションを変えたりしています。

#!/bin/sh
APIKEY=414e8804-2494-4dcd-bad1-534a30db272d
CERTIFICATE=$(/usr/bin/tail -n +2 /etc/letsencrypt/live/<証明書のCN>/cert.pem | /usr/bin/head -n -1 | /usr/bin/tr -d '\n')
PRIVATE_KEY=$(/usr/bin/tail -n +2 /etc/letsencrypt/live/<証明書のCN>/privkey.pem | /usr/bin/head -n -1 | /usr/bin/tr -d '\n')

curl --location --request POST 'https://<VyOSのFQDN>:<待ち受けポート>/configure' --form data="[{\"op\": \"set\", \"path\": [\"pki\", \"certificate\", \"<証明書名>\", \"certificate\", \"$CERTIFICATE\"]}, {\"op\": \"set\", \"path\": [\"pki\", \"certificate\", \"<証明書名>\", \"private\", \"key\", \"$PRIVATE_KEY\"]}]" --form key="$APIKEY"
curl --location --request POST 'https://<VyOSのFQDN>:<待ち受けポート>/config-file' --form data='{"op": "save"}' --form key="$APIKEY"

APIを使うことで、FWのルールを動的に開放するなど使い方が広がりますね。

おすすめ

コメントを残す

Amazon プライム対象