APISIX: FIPS 140-2 準拠を目指す

Jinhua Luo

January 6, 2023

Products

FIPS 140-2とは何か?

FIPSは、米国商務省の国立標準技術研究所(NIST)によって制定された、連邦情報処理標準の略称です。

FIPSの目的は、すべての連邦機関に対して、機密ではあるが非機密情報を保護するための統一されたセキュリティレベルを確立することです。これは、秘密情報やそれ以上の機密情報と見なされない電子データの大部分を保護するためのものです。

FIPS 140-2のセキュリティレベル

FIPS 140-2/3は、サイバーセキュリティの文脈で頻繁に使用される標準です。これらはどちらも、暗号モジュールの標準的なセキュリティ要件に関連しています。FIPS 140-3は最終的にFIPS 140-2に取って代わる予定であり、現在その移行が進行中です。

  • レベル1 – 最低限のセキュリティレベルで、すべてのコンポーネントが**「製品グレード」**であることを要求します。FIPS 140-2 レベル1は、特にソフトウェア暗号モジュールに関連し、使用可能な暗号アルゴリズムとその整合性を検証するために実施する必要がある自己テストについて規定しています。
  • レベル2物理的な改ざんの証拠役割ベースの認証に関する追加要件があります。
  • レベル3 – 攻撃者に対するセキュリティを強化するためのさらなる義務、IDベースの認証の使用、およびインターフェース間の物理的な分離が求められます。
  • レベル4 – 最も厳格なレベルで、環境攻撃に対する強力な物理的セキュリティ対策が必要です。

例えば、FIPS 140-2 レベル1で検証された暗号モジュールは、AESが提供するレベルの保護でデータを暗号化することで、基本的なセキュリティレベルを提供します。しかし、FIPS 140-2 レベル2で検証された暗号モジュールは、AESによる電子暗号化だけでなく、デバイス自体の物理的なセキュリティも提供します。

これは、FIPS 140-2 レベル2で検証された暗号モジュールは、ソリューションの筐体のシールが破られない限り改ざんされることがないことを意味します。そのような状況では、いわゆる暗号担当者が直ちに情報セキュリティが侵害されたことを知り、データ侵害を修復するための措置をすぐに取ることができます。

FIPSが重要な理由

FIPS 140-2で検証された暗号モジュールは、機密ではあるが非機密情報を扱うすべての米国連邦機関に対して法律で義務付けられています。 また、金融、医療、法律サービス、モバイルオペレーター、公共安全産業など、他の業界でもFIPS 140-2 レベル2をバックホールセキュリティの必須項目としています。

APISIXがFIPS 140-2に準拠

FIPS 140-2に準拠する方法

FIPSモードで動作するFIPS 140-2検証済みのOpenSSL 3.0ビルドと共に使用する場合、APISIXはSSL/TLS暗号化ネットワークトラフィックの復号化と暗号化に関してFIPS 140-2(レベル1)の要件に準拠しています。

影響

FIPSモードでは、以下の暗号が無効になります:

  • TLS_ECDH_anon_WITH_RC4_128_SHA
  • TLS_ECDHE_RSA_WITH_RC4_128_SHA
  • TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
  • TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
  • TLS_RSA_WITH_IDEA_CBC_SHA
  • TLS_RSA_WITH_RC4_128_MD5
  • TLS_RSA_WITH_RC4_128_SHA
  • TLS_RSA_WITH_SEED_CBC_SHA

また、FIPSは2048ビット未満のRSA鍵をサポートしません。

OpenSSLのビルド

FIPSを有効にしてOpenSSLをビルドおよびインストール

apt install -y build-essential
git clone https://github.com/openssl/openssl
cd openssl
./Configure --prefix=/usr/local/openssl-3.0 enable-fips
make install
bash -c "echo /usr/local/openssl-3.0/lib64 > /etc/ld.so.conf.d/openssl3.conf"
ldconfig
/usr/local/openssl-3.0/bin/openssl fipsinstall -out /usr/local/openssl-3.0/ssl/fipsmodule.cnf \
-module /usr/local/openssl-3.0/lib64/ossl-modules/fips.so
sed_expr='s@# .include fipsmodule.cnf@.include /usr/local/openssl-3.0/ssl/fipsmodule.cnf@g;'
sed_expr+=' s/# \(fips = fips_sect\)/\1\nbase = base_sect\n\n[base_sect]\nactivate=1\n/g'
sed -i "$sed_expr" /usr/local/openssl-3.0/ssl/openssl.cnf

bash -c "echo /usr/local/openssl-3.0/lib64 > /etc/ld.so.conf.d/openssl3.conf"
ldconfig

OpenSSLの検証

設定ファイル(/usr/local/openssl-3.0/ssl/openssl.cnf)を検証します。

以下のスニペットと一致することを確認してください:

config_diagnostics = 1
openssl_conf = openssl_init

.include /usr/local/ssl/fipsmodule.cnf

[openssl_init]
providers = provider_sect

[provider_sect]
fips = fips_sect
base = base_sect

[base_sect]
activate = 1

OpenSSLがSHA1ハッシュを実行できるかどうかを確認します:このテストは、OpenSSLの正しい動作を検証します。SHA1ハッシュアルゴリズムはすべてのモードで許可されているため、このコマンドが失敗した場合、OpenSSLの実装が正しく動作していないことを示します:

# openssl sha1 /dev/null
SHA1(/dev/null)= da39a3ee5e6b4b0d3255bfef95601890afd80709

OpenSSLがMD5ハッシュを実行できるかどうかを確認します:このテストは、OpenSSLがFIPSモードで実行されていることを検証します。MD5はFIPSモードで許可されていないハッシュアルゴリズムであるため、これを使用しようとすると失敗します:

# openssl md5 /dev/null
Error setting digest
80920FA8DA7F0000:error:0308010C:digital envelope routines:
inner_evp_generic_fetch:unsupported:crypto/evp/evp_fetch.c:341:
Global default library context, Algorithm (MD5 : 100), Properties ()

OpenSSLがFIPSモードで実行されていない場合、MD5ハッシュは正常に機能します:

# /usr/bin/openssl md5 /dev/null
MD5(/dev/null)= d41d8cd98f00b204e9800998ecf8427e

FIPS対応のAPISIXをビルド

# pcreとzlibの依存関係をインストール
wget -O - https://openresty.org/package/pubkey.gpg | apt-key add -
echo "deb http://openresty.org/package/${arch_path}ubuntu $(lsb_release -sc) main" | \
tee /etc/apt/sources.list.d/openresty.list
apt-get update
apt-get install -y openresty-pcre-dev openresty-zlib-dev

# コンパイルとリンクのオプションを指定
export zlib_prefix=/usr/local/openresty/zlib
export pcre_prefix=/usr/local/openresty/pcre
export cc_opt="-DNGX_LUA_ABORT_AT_PANIC -I${zlib_prefix}/include -I${pcre_prefix}/include"
cc_opt+="-I/usr/local/openssl-3.0/include"
export ld_opt="-L${zlib_prefix}/lib -L${pcre_prefix}/lib -L/usr/local/openssl-3.0/lib64"
ld_opt+="-Wl,-rpath,${zlib_prefix}/lib:${pcre_prefix}/lib:/usr/local/openssl-3.0/lib64"

# apisix-baseをビルドしてインストール
wget https://raw.githubusercontent.com/api7/apisix-build-tools/master/build-apisix-base.sh
bash build-apisix-base.sh latest

テストルートを設定

curl http://127.0.0.1:9180/apisix/admin/routes/httpbin -H 'X-API-KEY: YOUR-KEY' -X PUT -i -d '
{
    "uri": "/anything",
    "hosts": ["*.httpbin.org"],
    "methods": ["GET"],
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "httpbin.org": 1
        }
    }
}'

秘密鍵の検証をテスト

正常なケースをテストし、成功することを期待します。

証明書をアップロードするための補助的なPythonスクリプトを作成します:

cfg_ssl.py

import sys
import requests

if len(sys.argv) <= 3:
    print("bad argument")
    sys.exit(1)

with open(sys.argv[1]) as f:
    cert = f.read()

with open(sys.argv[2]) as f:
    key = f.read()

sni = sys.argv[3]
api_key = "edd1c9f034335f136f87ad84b625c8f1"

resp = requests.put("http://127.0.0.1:9180/apisix/admin/ssls/1", json={
    "cert": cert,
    "key": key,
    "snis": [sni],
}, headers={
    "X-API-KEY": api_key,
})
print(resp.status_code)
print(resp.text)

鍵生成を容易にするためのbash関数を作成します:

genkey() {
    keylen=${1:-4096}
    /usr/bin/openssl genrsa -out apisix.key $keylen
    /usr/bin/openssl req -key apisix.key -new -out apisix.csr -subj '/C=/ST=/L=/O=/OU=web/CN=*.httpbin.org'
    /usr/bin/openssl x509 -req -in apisix.csr -signkey apisix.key -out apisix.crt -days 3650 -sha256
}

テスト:

cd $(mktemp -d)
genkey 2048
python3 ssl.py apisix.crt apisix.key '*.httpbin.org'
curl --resolve 'www.httpbin.org:9443:127.0.0.1' https://www.httpbin.org:9443/uuid -vvv -k

出力:

...
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: OU=web; CN=*.httpbin.org
*  start date: Dec 22 05:52:58 2022 GMT
*  expire date: Dec 19 05:52:58 2032 GMT
*  issuer: OU=web; CN=*.httpbin.org
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55e125a24e30)
> GET /uuid HTTP/2
> Host: www.httpbin.org:9443
> user-agent: curl/7.68.0
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< content-type: application/json
< content-length: 53
< date: Thu, 22 Dec 2022 06:35:04 GMT
< access-control-allow-origin: *
< access-control-allow-credentials: true
< server: APISIX/3.0.0
<
{
  "uuid": "1827f239-376f-47ec-9b54-d5addaa8c7f9"
}

2048ビット未満の鍵をテスト

FIPSは2048ビット未満のRSA鍵をサポートしません。そのため、小さな鍵で失敗するかどうかをテストします。

genkey 1024
python3 cfg_ssl.py apisix.crt apisix.key '*.httpbin.org'
curl --resolve 'www.httpbin.org:9443:127.0.0.1' https://www.httpbin.org:9443/uuid -vvv -k

出力:

...
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
* Closing connection 0
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error

結論

FIPSが含む厳格なテストを考えると、これらは信頼できるセキュリティ標準と見なされます。さらに、インフラストラクチャ内でセキュリティ標準を実装する必要があるすべてのエンティティにとって有用なベースラインです。

APISIXにFIPSサポートを追加するのは簡単です。 APISIXは、FIPS 140-2 レベル1の準拠が必要な展開において、SSL/TLS暗号化ネットワークトラフィックの復号化と暗号化に使用できます。

APIゲートウェイに関する詳細情報については、ブログをご覧いただくか、お問い合わせください。

Tags: