From 632ed8bbb4a787a49e7c2fa170a25932bd24b965 Mon Sep 17 00:00:00 2001 From: Anurag Rajawat Date: Mon, 3 Jun 2024 19:09:03 +0530 Subject: [PATCH] feat: Add support for FIPS 140-3 encryption compliance check Signed-off-by: Anurag Rajawat --- Dockerfile | 2 +- config/addr.list | 2 + config/fips-140-3.json | 91 ++++++++++++++++++++++++++++++++++ k8s/job.yaml | 110 ++++++++++++++++++++++++++++++++++++++++- src/findings_tls | 88 +++++++++++++++++++++++++++++++-- src/tlsscan | 5 +- 6 files changed, 292 insertions(+), 6 deletions(-) create mode 100644 config/fips-140-3.json diff --git a/Dockerfile b/Dockerfile index 111d8d5..4822dcd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:latest +FROM ubuntu:22.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openssl ca-certificates curl netcat jq RUN curl -LO https://dl.k8s.io/release/v1.27.2/bin/linux/amd64/kubectl --output-dir /usr/local/bin/ && chmod +x /usr/local/bin/kubectl diff --git a/config/addr.list b/config/addr.list index 89101f3..2272a81 100644 --- a/config/addr.list +++ b/config/addr.list @@ -10,3 +10,5 @@ dh480.badssl.com:443 BadSSL isunknownaddress.com:12345 LocalTest localhost:9090 webserver localhost:22 localssh +apigateway-fips.us-east-1.amazonaws.com:443 AmazonAPIGateway +dynamodb-fips.ca-west-1.amazonaws.com:443 AmazonDynamoDB diff --git a/config/fips-140-3.json b/config/fips-140-3.json new file mode 100644 index 0000000..c8e8a03 --- /dev/null +++ b/config/fips-140-3.json @@ -0,0 +1,91 @@ +{ + "TLS_versions": [ + { + "TLS_version": "TLSv1.0_1.1", + "cipher_suites": [ + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" + } + ] + }, + { + "TLS_version": "TLSv1.2", + "cipher_suites": [ + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CCM" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CCM" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" + } + ] + }, + { + "TLS_version": "TLSv1.3", + "cipher_suites": [ + { + "cipher_suite": "TLS_AES_256_GCM_SHA384" + }, + { + "cipher_suite": "TLS_AES_128_GCM_SHA256" + }, + { + "cipher_suite": "TLS_AES_128_CCM_SHA256" + }, + { + "cipher_suite": "TLS_AES_128_CCM_8_SHA256" + } + ] + } + ] +} \ No newline at end of file diff --git a/k8s/job.yaml b/k8s/job.yaml index cd8611a..65b08bc 100755 --- a/k8s/job.yaml +++ b/k8s/job.yaml @@ -31,6 +31,106 @@ subjects: name: k8tls-serviceact namespace: k8tls --- +apiVersion: v1 +kind: ConfigMap +metadata: + name: k8tls-cm + namespace: k8tls +immutable: true +data: + fips-140-3.json: | + { + "TLS_versions": [ + { + "TLS_version": "TLSv1.0_1.1", + "cipher_suites": [ + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" + } + ] + }, + { + "TLS_version": "TLSv1.2", + "cipher_suites": [ + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CCM" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CCM" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" + }, + { + "cipher_suite": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384" + }, + { + "cipher_suite": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" + } + ] + }, + { + "TLS_version": "TLSv1.3", + "cipher_suites": [ + { + "cipher_suite": "TLS_AES_256_GCM_SHA384" + }, + { + "cipher_suite": "TLS_AES_128_GCM_SHA256" + }, + { + "cipher_suite": "TLS_AES_128_CCM_SHA256" + }, + { + "cipher_suite": "TLS_AES_128_CCM_8_SHA256" + } + ] + } + ] + } +--- apiVersion: batch/v1 kind: Job metadata: @@ -42,8 +142,16 @@ spec: serviceAccountName: k8tls-serviceact containers: - name: k8tls - image: kubearmor/k8tls:latest + image: kubearmor/k8tls:latest command: ["./k8s_tlsscan"] + volumeMounts: + - mountPath: /home/k8tls/config/ + name: config + readOnly: true restartPolicy: Never + volumes: + - name: config + configMap: + name: k8tls-cm backoffLimit: 4 --- diff --git a/src/findings_tls b/src/findings_tls index 5c8be6b..1276e37 100644 --- a/src/findings_tls +++ b/src/findings_tls @@ -5,8 +5,6 @@ opensslscan() tmp=/tmp/tls.out rm -f $tmp 2>/dev/null timeout 2s openssl s_client -CApath /etc/ssl/certs/ -connect "$SVC_Address" -brief < /dev/null 2>$tmp -# echo "ret=$ret" -# cat $tmp conn_estd=0 while read line; do [[ "$line" == "CONNECTION ESTABLISHED" ]] && conn_estd=1 @@ -18,6 +16,7 @@ opensslscan() printf -v "TLS_$key" '%s' "$val" TLS_Status="TLS" done < $tmp + fips_compliance_check [[ "$TLS_Verification_error" != "" ]] && TLS_Verification="$TLS_Verification_error" } @@ -25,7 +24,7 @@ tls_csvreport() { [[ "$csvout" == "" ]] && return cat << EOF >> $csvout -"$SVC_Name","$SVC_Address","$TLS_Status","$TLS_Protocol_version","$TLS_Ciphersuite","$TLS_Hash_used","$TLS_Signature_type","$TLS_Verification" +"$SVC_Name","$SVC_Address","$TLS_Status","$TLS_Protocol_version","$TLS_Ciphersuite","$TLS_Hash_used","$TLS_Signature_type","$TLS_Verification","$FIPS_140_3_Compliant" EOF } @@ -122,3 +121,86 @@ k8tls_tls_02certificateChecks() EOF } +fips_compliance_check() +{ + do_openssl_scan + if [ "$TLS_Status" != "TLS" ]; then + control_id="3.2" + description="Secure TLS protocol is required to meet the requirements of FIPS-140-3 compliant encryption." + severity="critical" + solution="Implement secure TLS protocol (TLS >= v1.2)" + FIPS_140_3_Compliant="No" + + appendSpec + return + fi + + control_id="3.3" + description="Approved ciphers to meet the requirements of FIPS-140-3 compliant encryption." + severity="medium" + + case "$TLS_Protocol_version" in + "TLSv1.1"|"TLSv1.0") + ciphers="`jq '.TLS_versions[0].cipher_suites[] | join(", ")' $FIPS_140_3_APPROVED_CIPHERS`" + solution="use FIPS-approved ciphers: [`echo $ciphers | sed 's/\"//g' | sed 's/ /, /g; s/, $//'`]" + FIPS_140_3_Compliant="No" + + result=$(jq ".TLS_versions[0].cipher_suites[] | select(.cipher_suite == \"$TLS_Ciphersuite\") | any" "$FIPS_140_3_APPROVED_CIPHERS") + + [[ $result == "true" ]] && { + FIPS_140_3_Compliant="Yes" + description="Using Secure TLS protocol and FIPS-approved Ciphers. FIPS-approved ciphersuite in use is $TLS_Ciphersuite" + solution="NA" + } + ;; + + "TLSv1.2") + ciphers="`jq '.TLS_versions[1].cipher_suites[] | join(", ")' $FIPS_140_3_APPROVED_CIPHERS`" + solution="use FIPS-approved ciphers: [`echo $ciphers | sed 's/\"//g' | sed 's/ /, /g; s/, $//'`]" + FIPS_140_3_Compliant="No" + + result=$(jq ".TLS_versions[1].cipher_suites[] | select(.cipher_suite == \"$TLS_Ciphersuite\") | any" "$FIPS_140_3_APPROVED_CIPHERS") + + [[ $result == "true" ]] && { + FIPS_140_3_Compliant="Yes" + description="Using Secure TLS protocol and FIPS-approved Ciphers. FIPS-approved ciphersuite in use is $TLS_Ciphersuite" + solution="NA" + } + ;; + + "TLSv1.3") + ciphers="`jq '.TLS_versions[2].cipher_suites[] | join(", ")' $FIPS_140_3_APPROVED_CIPHERS`" + solution="use FIPS-approved ciphers: [`echo $ciphers | sed 's/\"//g' | sed 's/ /, /g; s/, $//'`]" + FIPS_140_3_Compliant="No" + + result=$(jq ".TLS_versions[2].cipher_suites[] | select(.cipher_suite == \"$TLS_Ciphersuite\") | any" "$FIPS_140_3_APPROVED_CIPHERS") + + [[ $result == "true" ]] && { + FIPS_140_3_Compliant="Yes" + description="Using Secure TLS protocol and FIPS-approved Ciphers. FIPS-approved ciphersuite in use is $TLS_Ciphersuite" + solution="NA" + } + ;; + esac + + appendSpec +} + +appendSpec() +{ + cat << EOF >> $TMPJSONSEC + { + "plugin": "fips-140-3-compliance-check", + "title": "FIPS 140-3 compliant encryption check", + "compliance": "FIPS.140.3", + "control-id": "$control_id", + "cipherSuiteInUse": "$TLS_Ciphersuite", + "description": "$description", + "link": "https://www.gsa.gov/system/files?file=SSL-TLS-Implementation-%5BCIO-IT-Security-14-69-Rev-7%5D-06-12-2023.pdf", + "severity": "$severity", + "remediationEstEffort": "medium", + "solution": "$solution", + "compliant": "$FIPS_140_3_Compliant" + }, +EOF +} diff --git a/src/tlsscan b/src/tlsscan index 78e4859..bc5e669 100755 --- a/src/tlsscan +++ b/src/tlsscan @@ -1,6 +1,7 @@ #!/bin/bash BDIR=`dirname $0` +FIPS_140_3_APPROVED_CIPHERS="config/fips-140-3.json" chk_cmd() { if ! command -v $1 &>/dev/null; then @@ -57,7 +58,7 @@ csvheader() { [[ "$csvout" == "" ]] && return if [ ! -f "$csvout" ]; then - echo "Name,Address,Status,Version,Ciphersuite,Hash,Signature,Verification" > $csvout + echo "Name,Address,Status,Version,Ciphersuite,Hash,Signature,Verification,FIPS_140_3_Compliant" > $csvout fi } @@ -128,12 +129,14 @@ getsummary() "self-signed certificate" "insecure port" "connection failure" + "FIPS 140-3 non-compliant" ) regex_arr=( "certificate has expired" "self-signed certificate" "PLAIN_TEXT" "CONNFAIL" + "No" ) echo "Status,Count" > $summcsv for((i=0;;i++)); do