Created
January 26, 2025 22:05
-
-
Save cclloyd/873cd1cb96260b8ce4152b6ae918db7c to your computer and use it in GitHub Desktop.
Copy LetsEncrypt ACME Certificates from OPNSense to Kubernetes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/bash | |
# | |
# This script takes any certificates found from the ACME client plugin in OPNSense and copies them to one or more namespaces in kubernetes. | |
# Useful for setting as an automation script in the ACME plugin. | |
# | |
# Required env variables: KUBE_TOKEN, KUBE_HOST | |
# Optional variables: KUBE_PORT, NAMESPACES (space separated string of namespaces) | |
# | |
# NOTE: This script requires you to install base64 and bash. Run `pkg install base64 bash` | |
# | |
BASE_DIR="/var/etc/acme-client" | |
KUBE_API="https://${KUBE_HOST}:${KUBE_PORT:-6443}" | |
NAMESPACES=($(echo "${KUBE_NAMESPACES:-default}")) | |
[ -z "${KUBE_HOST}" ] && echo "Error: KUBE_HOST is not set." && exit 1 | |
[ -z "${KUBE_TOKEN}" ] && echo "Error: KUBE_TOKEN is not set." && exit 1 | |
# Iterate over each folder in the certificates directory | |
for CERT_DIR in "$BASE_DIR/certs/"*; do | |
# Check if it's a directory | |
[[ -d "$CERT_DIR" ]] || continue | |
FOLDER_NAME=$(basename "$CERT_DIR") | |
FULLCHAIN_FILE="$BASE_DIR/certs/$FOLDER_NAME/fullchain.pem" | |
PRIVATE_KEY_FILE="$BASE_DIR/keys/$FOLDER_NAME/private.key" | |
# Check if the required files exist | |
[[ -f "$FULLCHAIN_FILE" ]] || { echo "Fullchain file not found in $BASE_DIR/certs/$FOLDER_NAME. Skipping..."; continue; } | |
[[ -f "$PRIVATE_KEY_FILE" ]] || { echo "Private key file not found in $BASE_DIR/keys/$FOLDER_NAME. Skipping..."; continue; } | |
COMMON_NAME=$(openssl x509 -noout -subject -in "$FULLCHAIN_FILE" | sed -n 's/.*CN = \(.*\)/\1/p') | |
echo "Found cert with common name: $COMMON_NAME" | |
# Base64 encode the files | |
FULLCHAIN_CONTENT=$(cat "$FULLCHAIN_FILE" | base64 | tr -d '\n') | |
PRIVATE_KEY_CONTENT=$(cat "$PRIVATE_KEY_FILE" | base64 | tr -d '\n') | |
SECRET_NAME="tls-$COMMON_NAME" | |
# Create the JSON payload for the secret | |
SECRET_JSON=$(cat <<EOF | |
{ | |
"apiVersion": "v1", | |
"kind": "Secret", | |
"metadata": { | |
"name": "$SECRET_NAME", | |
"namespace": "$KUBE_NAMESPACE" | |
}, | |
"type": "kubernetes.io/tls", | |
"data": { | |
"tls.crt": "$FULLCHAIN_CONTENT", | |
"tls.key": "$PRIVATE_KEY_CONTENT" | |
} | |
} | |
EOF | |
) | |
# Iterate over each namespace provided | |
for KUBE_NAMESPACE in "${NAMESPACES[@]}"; do | |
echo "Processing namespace: $KUBE_NAMESPACE" | |
# Check if the secret already exists | |
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -k -H "Authorization: Bearer $KUBE_TOKEN" "$KUBE_API/api/v1/namespaces/$KUBE_NAMESPACE/secrets/$SECRET_NAME") | |
if [[ "$RESPONSE" == "200" ]]; then | |
echo "Updating existing secret: $SECRET_NAME in namespace $KUBE_NAMESPACE" | |
UPDATE_RESPONSE=$(curl -s -o /tmp/update_output -w "%{http_code}" -k -X PUT \ | |
-H "Authorization: Bearer $KUBE_TOKEN" \ | |
-H "Content-Type: application/json" \ | |
-d "$SECRET_JSON" \ | |
"$KUBE_API/api/v1/namespaces/$KUBE_NAMESPACE/secrets/$SECRET_NAME") | |
if [[ "$UPDATE_RESPONSE" != "200" ]]; then | |
echo "Failed to update secret: $SECRET_NAME in namespace $KUBE_NAMESPACE" | |
echo "Status Code: $UPDATE_RESPONSE" | |
echo "Error Response: $(cat /tmp/update_output)" | |
else | |
echo "Secret $SECRET_NAME updated successfully in namespace $KUBE_NAMESPACE." | |
fi | |
else | |
echo "Creating new secret: $SECRET_NAME in namespace $KUBE_NAMESPACE" | |
CREATE_RESPONSE=$(curl -s -o /tmp/create_output -w "%{http_code}" -k -X POST \ | |
-H "Authorization: Bearer $KUBE_TOKEN" \ | |
-H "Content-Type: application/json" \ | |
-d "$SECRET_JSON" \ | |
"$KUBE_API/api/v1/namespaces/$KUBE_NAMESPACE/secrets") | |
if [[ "$CREATE_RESPONSE" != "201" ]]; then | |
echo "Failed to create secret: $SECRET_NAME in namespace $KUBE_NAMESPACE" | |
echo "Status Code: $CREATE_RESPONSE" | |
echo "Error Response: $(cat /tmp/create_output)" | |
else | |
echo "Secret $SECRET_NAME created successfully in namespace $KUBE_NAMESPACE." | |
fi | |
fi | |
done | |
echo "Processed secret for $COMMON_NAME in all namespaces" | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment