それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

OPNSenseのAPIでファイアウォールのAliasを更新する。API利用例

OPNSense設定を更新したいのでAPIを利用する

OPNSenseの設定を更新しようと思うと、APIを使うのが手っ取り早い。

APIJSONでGET/POSTができる。APIで設定を取得したり、更新したりができる。

https://docs.opnsense.org/development/api/core/firewall.htmlAPIの一覧がある

APIの使い方の調べ方

APIは、管理画面で使わている。だからドキュメント以外にも管理画面のリクエストを凝視すれば、使い方がわかる。

管理画面のAPIリクエストの例

f:id:takuya_1st:20220401143130p:plain

API を叩く準備:キー発行

APIを叩くには、キーを発行する。

キーは、「システム:→アクセス→ ユーザ→API 鍵→(+)ボタン」を押す。

(+)ボタンを押すと、キーがダウンロードされるので、それを変数に入れて使う。

キー発行は、ログインでもできる。ログインURLをcURLで叩いて、ワンタイムキーを取得する方法も取れる。ただパスワードをソース記載するのも面倒だしAPI鍵管理機能を使うのが楽だと思う。

API リクエスト例:ダッシュボード

管理画面のダッシュボードにある情報を取得する例

key=XXXXXXXXXXXXXXXbVt0mM8IEUv
secret=XXXXXXXXXXXXXX162pKmFQ
/usr/bin/curl --silent \
  --basic \
  --user "$key:$secret" \
  --insecure \
  https://192.168.1.1/api/diagnostics/activity/getActivity \
| jq .headers

cURLでリクエストを送信し、結果をJSONで受け取る。

JSONで受け取るので、jq と組み合わせて欲しいデータを取る。

APIリクエスト例:ファイアウォールエイリアス

OPNSenseの目玉機能である、ファイアウォールの「エイリアス」機能にアクセスしてみる。

key=XXXXXXXXXXXXXXXbVt0mM8IEUv
secret=XXXXXXXXXXXXXX162pKmFQ
curl \
  --basic \
  --user "$key:$secret" \
  --insecure \
  --verbose \
  https://192.168.1.1/api/firewall/alias/get  \
> out.json
cat out.json | jq .

エイリアスの一覧で、すべての情報を取得することができる

jq による整形

データは非常に多いので、jq でいい感じにフィルタ掛けてあげる

cat out.json | jq '.alias.aliases.alias | to_entries[] |  select( .value.name | test("my-alias-name") ) '

OPNSenseのレスポンスは、無駄のないきれいなJSONになっている。綺麗すぎてjq で処理しづらいので、 to_entries[] を使って変換する

to_entries[] を使う

to_entries[] を使うと、{ "uuid_a" { entry } } を ` { key:'uuid_a', value: { entry } } に変換できる

to_entries[] する前

{
   "id_1" : {
       age: 100
    }
   "id_2" : {
       age: 99
    }
}

to_entries[] を通した後

[
  {  key:"id_1",  value: {  age:100 } ,
  {  key:"id_2",  value: {  age:99 } ,
]

となる。

意図的に冗長なJSONに書き換えて、jqフィルタ処理が行いやすくできる。

jq 使ってJSONを整形したりフィルタする時の必須テクである。

API リクエスト POST 例:ファイアウォールエイリアス更新

ファイアウォールエイリアスにPOSTして更新する。

curl 'https://192.168.1.1/api/firewall/alias/setItem/1234567asdfghj' \
  -H 'content-type: application/json' \
  --data-raw '{"alias":{"enabled":"1",(中略)ent":""}' \
  --compressed \
  --insecure

POSTするデータは、管理画面のリクエストを見たほうが速い。

なのでcurl コマンドをChromeから取得 f:id:takuya_1st:20220401144939p:plain

実際にリクエストを作成するポイント

実際にリクエストを作成するとき、JSONをPOSTする。

一般的にJSONのPOSTをする場合、次のようになる。

curl http:///xxxxx  \
  -X POST
  -H 'content-type: application/json' \
  --data-raw '{"alias": ...... '

json を1行にまとめる。

curl--data-raw に使えるように、JSONを1行にまとめる。

JSONは改行をしてこそ人間が見やすい形式になる。しかし、プログラムで扱うには、改行が邪魔である。

jq -cjson を1行にまとめる。
cat req-data.json | jq -c . 

ここまでをまとめる。

ここまで調べたことをまとめて、OPNSenseのファイアウォールのAliisを更新するAPIコールを書いてみる。

function ip_list_to_content(){
  IPs=$1;
  IPs=$( echo $IPs | sed 's|\s|\\n|g' ) 
  echo $IPs
}
function build_firewall_alias_json(){
  name=$1
  body=$2
  description=$3
  JSON="
  {
    'alias':{
      'enabled':'1',
      'name':'${name}',
      'type':'network',
      'proto':'',
      'updatefreq':'',
      'content': '${body}',
      'interface':'',
      'counters':'0',
      'description':'${description}',
      'network_content':''
    }
  }"
  echo $JSON | sed -r "s|'|\"|g"
  
}
function json_req_param(){
  JSON=$1
  echo $JSON | jq -c . 
}
function post_to_opnsense(){
  URL=$1
  curl \
    --silent \
    --basic \
    --user "$key:$secret" \
    --insecure \
    -X POST \
    --data "${body}" \
    -H "Content-Type: application/json" \
    $URL
}
function get_to_opnsense(){
  
  URL=$1
  curl \
    --silent \
    --basic \
    --user "$key:$secret" \
    --insecure \
    $URL
}
function getItem_Of_Fw_Alias(){
  name=$1
  filter=".alias.aliases.alias | to_entries[] |  select( .value.name | test(\"${name}\") ) "
  URL="https://${OPNSenseAddr}/api/firewall/alias/get"
  get_to_opnsense $URL| jq -r "${filter}"
}
function get_UUID_by_name(){
  name=$1
  getItem_Of_Fw_Alias $name | jq -r .key
}

function google_smtp_ips(){
  for i in $( dig txt  _spf.google.com +short | \grep -Po '(?<=include:)[^\s]+' ); do
    dig $i +short  txt  | \grep -Po '(?<=ip4:)[0-9\./]+';
  done | uniq | sort -n
}
function update_fw_alias_google_smtp(){
  desc="GoogleのSMTPサーバー(spfから取得)"
  name="Google_SMTP"
  uuid=$( get_UUID_by_name $name )
  ip_list=$(google_smtp_ips)
  content=$( ip_list_to_content "${ip_list}" )
  json=$( build_firewall_alias_json $name $content $desc )
  body=$( json_req_param "$json" ) 
  URL="https://${OPNSenseAddr}/api/firewall/alias/setItem/${uuid}"
  ret=$(post_to_opnsense $URL $body )
  echo $name
  echo $ret | jq . 
}

function update_fw_alias_cloudflare_ipv4(){
  desc="Cloudflare ip list"
  name="Cloudflare"
  uuid=$( get_UUID_by_name $name )
  ip_list=$( curl -s https://www.cloudflare.com/ips-v4 )
  content=$( ip_list_to_content "${ip_list}" )
  json=$( build_firewall_alias_json $name $content $desc )
  body=$( json_req_param "$json" ) 
  URL="https://${OPNSenseAddr}/api/firewall/alias/setItem/${uuid}"
  ret=$(post_to_opnsense $URL $body )
  echo $name
  echo $ret | jq .
}

function main(){
  key=zzzzz/0mM8IEUv....
  secret=.....Aj4AC3+3EC5...
  OPNSenseAddr=192.168.1.1
  ## 
  update_fw_alias_google_smtp;
  ## 
  update_fw_alias_cloudflare_ipv4;
}



main;