From 017a10189c9a8d38c95b8d2631a1facf181a6549 Mon Sep 17 00:00:00 2001 From: Avi Miller Date: Fri, 18 Jun 2021 10:16:32 +1000 Subject: [PATCH] fix: switch to using functions instead of calling OpenSSL directly Also reduced the number of environment variables which simplifies the documentation and requirements. The variable names now match those used by the OCI CLI. Signed-off-by: Avi Miller --- dnsapi/dns_oci.sh | 120 ++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 62 deletions(-) diff --git a/dnsapi/dns_oci.sh b/dnsapi/dns_oci.sh index 2843a8ca..1c75b99f 100644 --- a/dnsapi/dns_oci.sh +++ b/dnsapi/dns_oci.sh @@ -3,15 +3,16 @@ # Acme.sh DNS API plugin for Oracle Cloud Infrastructure # Copyright (c) 2021, Oracle and/or its affiliates # -# Required environment variables: -# - OCI_TENANCY : OCID of tenancy that contains the target DNS zone -# - OCI_USER : OCID of user with permission to add/remove records from zones -# - OCI_FINGERPRINT: fingerprint of the public key for the user -# - OCI_PRIVATE_KEY: Path to private API signing key file in PEM format +# Required OCI CLI environment variables: +# - OCI_CLI_TENANCY : OCID of tenancy that contains the target DNS zone +# - OCI_CLI_USER : OCID of user with permission to add/remove records from zones +# - OCI_CLI_REGION : Should point to the tenancy home region # -# Optional environment variables: -# - OCI_KEY_PASSPHRASE: if the private key above s encrypted, the passphrase is required -# - OCI_REGION: Your home region will probably response the fastest +# One of the following two variables is required: +# - OCI_CLI_KEY_FILE: Path to private API signing key file in PEM format; or +# - OCI_CLI_KEY : The private API signing key in PEM format +# +# NOTE: using an encrypted private key that needs a passphrase is not supported. # dns_oci_add() { @@ -20,11 +21,6 @@ dns_oci_add() { if _oci_config; then - if ! _get_zone "$_fqdn"; then - _err "Error: DNS Zone not found for $_fqdn." - return 1 - fi - if [ "$_sub_domain" ] && [ "$_domain" ]; then _add_record_body="{\"items\":[{\"domain\":\"${_sub_domain}.${_domain}\",\"rdata\":\"$_rdata\",\"rtype\":\"TXT\",\"ttl\": 30,\"operation\":\"ADD\"}]}" response=$(_signed_request "PATCH" "/20180115/zones/${_domain}/records" "$_add_record_body") @@ -48,11 +44,6 @@ dns_oci_rm() { if _oci_config; then - if ! _get_zone "$_fqdn"; then - _err "Error: DNS Zone not found for $_fqdn." - return 1 - fi - if [ "$_sub_domain" ] && [ "$_domain" ]; then _remove_record_body="{\"items\":[{\"domain\":\"${_sub_domain}.${_domain}\",\"rdata\":\"$_rdata\",\"rtype\":\"TXT\",\"operation\":\"REMOVE\"}]}" response=$(_signed_request "PATCH" "/20180115/zones/${_domain}/records" "$_remove_record_body") @@ -73,59 +64,57 @@ dns_oci_rm() { #################### Private functions below ################################## _oci_config() { - OCI_TENANCY="${OCI_TENANCY:-$(_readaccountconf_mutable OCI_TENANCY)}" - OCI_USER="${OCI_USER:-$(_readaccountconf_mutable OCI_USER)}" - OCI_FINGERPRINT="${OCI_FINGERPRINT:-$(_readaccountconf_mutable OCI_FINGERPRINT)}" - OCI_PRIVATE_KEY="${OCI_PRIVATE_KEY:-$(_readaccountconf_mutable OCI_PRIVATE_KEY)}" - OCI_KEY_PASSPHRASE="${OCI_KEY_PASSPHRASE:-$(_readaccountconf_mutable OCI_KEY_PASSPHRASE)}" - OCI_REGION="${OCI_REGION:-$(_readaccountconf_mutable OCI_REGION)}" + OCI_CLI_TENANCY="${OCI_CLI_TENANCY:-$(_readaccountconf_mutable OCI_CLI_TENANCY)}" + OCI_CLI_USER="${OCI_CLI_USER:-$(_readaccountconf_mutable OCI_CLI_USER)}" + OCI_CLI_KEY="${OCI_CLI_KEY:-$(_readaccountconf_mutable OCI_CLI_KEY)}" + OCI_CLI_REGION="${OCI_CLI_REGION:-$(_readaccountconf_mutable OCI_CLI_REGION)}" _not_set="" _ret=0 - if [ -f "$OCI_PRIVATE_KEY" ]; then - OCI_PRIVATE_KEY="$(openssl enc -a -A <"$OCI_PRIVATE_KEY")" + if [ -z "$OCI_CLI_KEY_FILE" ] && [ -z "$OCI_CLI_KEY" ]; then + _err "Fatal: you must provide a value for either OCI_CLI_KEY_FILE or OCI_CLI_KEY." + return 1 fi - if [ -z "$OCI_TENANCY" ]; then - _not_set="OCI_TENANCY " + if [ "$OCI_CLI_KEY_FILE" ] && [ -z "$OCI_CLI_KEY" ]; then + if [ -f "$OCI_CLI_KEY_FILE" ]; then + OCI_CLI_KEY=$(_base64 <"$OCI_CLI_KEY_FILE") + else + _err "Fatal: unable to read $OCI_CLI_KEY_FILE." + return 1 + fi fi - if [ -z "$OCI_USER" ]; then - _not_set="${_not_set}OCI_USER " + if [ -z "$OCI_CLI_TENANCY" ]; then + _not_set="${_not_set}OCI_CLI_TENANCY " fi - if [ -z "$OCI_FINGERPRINT" ]; then - _not_set="${_not_set}OCI_FINGERPRINT " + if [ -z "$OCI_CLI_USER" ]; then + _not_set="${_not_set}OCI_CLI_USER " fi - if [ -z "$OCI_PRIVATE_KEY" ]; then - _not_set="${_not_set}OCI_PRIVATE_KEY" + if [ -z "$OCI_CLI_REGION" ]; then + _not_set="${_not_set}OCI_CLI_REGION " fi if [ "$_not_set" ]; then - _err "Fatal: environment variable(s): ${_not_set} not set." + _err "Fatal: required environment variable(s): ${_not_set} not set." _ret=1 else - _saveaccountconf_mutable OCI_TENANCY "$OCI_TENANCY" - _saveaccountconf_mutable OCI_USER "$OCI_USER" - _saveaccountconf_mutable OCI_FINGERPRINT "$OCI_FINGERPRINT" - _saveaccountconf_mutable OCI_PRIVATE_KEY "$OCI_PRIVATE_KEY" + _saveaccountconf_mutable OCI_CLI_TENANCY "$OCI_CLI_TENANCY" + _saveaccountconf_mutable OCI_CLI_USER "$OCI_CLI_USER" + _saveaccountconf_mutable OCI_CLI_KEY "$OCI_CLI_KEY" + _saveaccountconf_mutable OCI_CLI_REGION "$OCI_CLI_REGION" fi - if [ "$OCI_PRIVATE_KEY" ] && [ "$(printf "%s\n" "$OCI_PRIVATE_KEY" | wc -l)" -eq 1 ]; then - OCI_PRIVATE_KEY="$(echo "$OCI_PRIVATE_KEY" | openssl enc -d -a -A)" - _secure_debug3 OCI_PRIVATE_KEY "$OCI_PRIVATE_KEY" + if ! _contains "PRIVATE KEY" "$OCI_CLI_KEY"; then + OCI_CLI_KEY=$(printf "%s" "$OCI_CLI_KEY" | _dbase64 multiline) fi - if [ "$OCI_KEY_PASSPHRASE" ]; then - _saveaccountconf_mutable OCI_KEY_PASSPHRASE "$OCI_KEY_PASSPHRASE" - fi - - if [ "$OCI_REGION" ]; then - _saveaccountconf_mutable OCI_REGION "$OCI_REGION" - else - OCI_REGION="us-ashburn-1" + if ! _get_zone "$_fqdn"; then + _err "Error: DNS Zone not found for $_fqdn." + _ret=1 fi return $_ret @@ -168,6 +157,19 @@ _get_zone() { } +#Usage: privatekey +#Output MD5 fingerprint +_fingerprint() { + pkey="$1" + if [ -z "$pkey" ]; then + _usage "Usage: _fingerprint privkey" + return 1 + fi + + printf "%s" "$pkey" | ${ACME_OPENSSL_BIN:-openssl} rsa -pubout -outform DER 2>/dev/null | ${ACME_OPENSSL_BIN:-openssl} md5 -c | cut -d = -f 2 | tr -d ' ' + +} + _signed_request() { _sig_method="$1" @@ -175,17 +177,13 @@ _signed_request() { _sig_body="$3" _return_field="$4" - _sig_host="dns.$OCI_REGION.oraclecloud.com" - _sig_keyId="$OCI_TENANCY/$OCI_USER/$OCI_FINGERPRINT" + _key_fingerprint=$(_fingerprint "$OCI_CLI_KEY") + _sig_host="dns.$OCI_CLI_REGION.oraclecloud.com" + _sig_keyId="$OCI_CLI_TENANCY/$OCI_CLI_USER/$_key_fingerprint" _sig_alg="rsa-sha256" _sig_version="1" _sig_now="$(LC_ALL=C \date -u "+%a, %d %h %Y %H:%M:%S GMT")" - if [ "$OCI_KEY_PASSPHRASE" ]; then - export OCI_KEY_PASSPHRASE="$OCI_KEY_PASSPHRASE" - _sig_passinArg="-passin env:OCI_KEY_PASSPHRASE" - fi - _request_method=$(printf %s "$_sig_method" | _lower_case) _curl_method=$(printf %s "$_sig_method" | _upper_case) @@ -198,7 +196,7 @@ _signed_request() { if [ "$_sig_body" ]; then _secure_debug3 _sig_body "$_sig_body" - _sig_body_sha256="x-content-sha256: $(printf %s "$_sig_body" | openssl dgst -binary -sha256 | openssl enc -e -base64)" + _sig_body_sha256="x-content-sha256: $(printf %s "$_sig_body" | _digest sha256)" _sig_body_type="content-type: application/json" _sig_body_length="content-length: ${#_sig_body}" _string_to_sign="$_string_to_sign\n$_sig_body_sha256\n$_sig_body_type\n$_sig_body_length" @@ -207,10 +205,8 @@ _signed_request() { _tmp_file=$(_mktemp) if [ -f "$_tmp_file" ]; then - printf '%s' "$OCI_PRIVATE_KEY" >"$_tmp_file" - # Double quoting the file and passphrase breaks openssl - # shellcheck disable=SC2086 - _signature=$(printf '%b' "$_string_to_sign" | openssl dgst -sha256 -sign $_tmp_file $_sig_passinArg | openssl enc -e -base64 | tr -d '\r\n') + printf '%s' "$OCI_CLI_KEY" >"$_tmp_file" + _signature=$(printf '%b' "$_string_to_sign" | _sign "$_tmp_file" sha256 | tr -d '\r\n') rm -f "$_tmp_file" fi