APISIX: FIPS 140-2 준수하기

Jinhua Luo

January 6, 2023

Products

FIPS 140-2란 무엇인가요?

FIPS는 미국 연방 상무부의 국립표준기술연구소(NIST)에서 제정한 컴퓨터 보안 표준인 Federal Information Processing Standards의 약자입니다.

FIPS의 목표는 모든 연방 기관이 민감하지만 비밀 등급이 아닌 정보를 보호하기 위해 일관된 보안 수준을 만드는 것입니다. 이는 비밀이나 그 이상의 등급으로 간주되지 않는 전자 데이터의 상당 부분을 포함합니다.

FIPS 140-2의 보안 수준

FIPS 140-2/3는 사이버 보안 분야에서 자주 사용되는 표준입니다. 이 두 표준은 모두 암호화 모듈에 대한 표준 보안 요구사항과 관련이 있습니다. FIPS 140-3는 결국 FIPS 140-2를 대체할 예정이며, 현재 이 전환 작업이 진행 중입니다.

  • 레벨 1 – 최소 요구사항을 부과하는 가장 낮은 보안 수준으로, 모든 구성 요소가 **'생산 등급'**이어야 합니다. FIPS 140-2 레벨 1은 특히 소프트웨어 암호화 모듈과 관련이 있으며, 사용할 수 있는 암호화 알고리즘과 그 무결성을 검증하기 위해 수행해야 하는 자체 테스트에 대한 규정을 포함합니다.
  • 레벨 2물리적 변조 증거역할 기반 인증에 대한 추가 요구사항이 있습니다.
  • 레벨 3 – 공격자에 대한 보안 강화, 신원 기반 인증 사용, 그리고 인터페이스 간의 물리적 분리에 대한 추가 의무가 있습니다.
  • 레벨 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 빌드

# install pcre and zlib dependencies
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

# specify compile and link options
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"

# build and install 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
        }
    }
}'

개인 키 검증 테스트

정상적인 경우를 테스트하여 성공할 것으로 예상합니다.

인증서를 업로드하기 위한 보조 파이썬 스크립트 생성:

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: