123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- #!/usr/bin/env sh
- # shellcheck disable=SC2034
- dns_openstack_info='OpenStack Designate API
- Depends on OpenStackClient and python-desginateclient.
- You will require Keystone V3 credentials loaded into your environment,
- which could be either password or v3 application credential type.
- Site: docs.openstack.org/api-ref/dns/
- Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_openstack
- Options:
- OS_AUTH_URL Auth URL. E.g. "https://keystone.example.com:5000/"
- OS_USERNAME Username
- OS_PASSWORD Password
- OS_PROJECT_NAME Project name
- OS_PROJECT_DOMAIN_NAME Project domain name. E.g. "Default"
- OS_USER_DOMAIN_NAME User domain name. E.g. "Default"
- Issues: github.com/acmesh-official/acme.sh/issues/3054
- Author: Andy Botting <[email protected]>
- '
- ######## Public functions #####################
- # Usage: dns_openstack_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
- dns_openstack_add() {
- fulldomain=$1
- txtvalue=$2
- _debug fulldomain "$fulldomain"
- _debug txtvalue "$txtvalue"
- _dns_openstack_credentials || return $?
- _dns_openstack_check_setup || return $?
- _dns_openstack_find_zone || return $?
- _dns_openstack_get_recordset || return $?
- _debug _recordset_id "$_recordset_id"
- if [ -n "$_recordset_id" ]; then
- _dns_openstack_get_records || return $?
- _debug _records "$_records"
- fi
- _dns_openstack_create_recordset || return $?
- }
- # Usage: dns_openstack_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
- # Remove the txt record after validation.
- dns_openstack_rm() {
- fulldomain=$1
- txtvalue=$2
- _debug fulldomain "$fulldomain"
- _debug txtvalue "$txtvalue"
- _dns_openstack_credentials || return $?
- _dns_openstack_check_setup || return $?
- _dns_openstack_find_zone || return $?
- _dns_openstack_get_recordset || return $?
- _debug _recordset_id "$_recordset_id"
- if [ -n "$_recordset_id" ]; then
- _dns_openstack_get_records || return $?
- _debug _records "$_records"
- fi
- _dns_openstack_delete_recordset || return $?
- }
- #################### Private functions below ##################################
- _dns_openstack_create_recordset() {
- if [ -z "$_recordset_id" ]; then
- _info "Creating a new recordset"
- if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record="$txtvalue" "$_zone_id" "$fulldomain."); then
- _err "No recordset ID found after create"
- return 1
- fi
- else
- _info "Updating existing recordset"
- # Build new list of --record=<rec> args for update
- _record_args="--record=$txtvalue"
- for _rec in $_records; do
- _record_args="$_record_args --record=$_rec"
- done
- # shellcheck disable=SC2086
- if ! _recordset_id=$(openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain."); then
- _err "Recordset update failed"
- return 1
- fi
- fi
- _max_retries=60
- _sleep_sec=5
- _retry_times=0
- while [ "$_retry_times" -lt "$_max_retries" ]; do
- _retry_times=$(_math "$_retry_times" + 1)
- _debug3 _retry_times "$_retry_times"
- _record_status=$(openstack recordset show -c status -f value "$_zone_id" "$_recordset_id")
- _info "Recordset status is $_record_status"
- if [ "$_record_status" = "ACTIVE" ]; then
- return 0
- elif [ "$_record_status" = "ERROR" ]; then
- return 1
- else
- _sleep $_sleep_sec
- fi
- done
- _err "Recordset failed to become ACTIVE"
- return 1
- }
- _dns_openstack_delete_recordset() {
- if [ "$_records" = "$txtvalue" ]; then
- _info "Only one record found, deleting recordset"
- if ! openstack recordset delete "$_zone_id" "$fulldomain." >/dev/null; then
- _err "Failed to delete recordset"
- return 1
- fi
- else
- _info "Found existing records, updating recordset"
- # Build new list of --record=<rec> args for update
- _record_args=""
- for _rec in $_records; do
- if [ "$_rec" = "$txtvalue" ]; then
- continue
- fi
- _record_args="$_record_args --record=$_rec"
- done
- # shellcheck disable=SC2086
- if ! openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain." >/dev/null; then
- _err "Recordset update failed"
- return 1
- fi
- fi
- }
- _dns_openstack_get_root() {
- # Take the full fqdn and strip away pieces until we get an exact zone name
- # match. For example, _acme-challenge.something.domain.com might need to go
- # into something.domain.com or domain.com
- _zone_name=$1
- _zone_list=$2
- while [ "$_zone_name" != "" ]; do
- _zone_name="$(echo "$_zone_name" | sed 's/[^.]*\.*//')"
- echo "$_zone_list" | while read -r id name; do
- if _startswith "$_zone_name." "$name"; then
- echo "$id"
- fi
- done
- done | _head_n 1
- }
- _dns_openstack_find_zone() {
- if ! _zone_list="$(openstack zone list -c id -c name -f value)"; then
- _err "Can't list zones. Check your OpenStack credentials"
- return 1
- fi
- _debug _zone_list "$_zone_list"
- if ! _zone_id="$(_dns_openstack_get_root "$fulldomain" "$_zone_list")"; then
- _err "Can't find a matching zone. Check your OpenStack credentials"
- return 1
- fi
- _debug _zone_id "$_zone_id"
- }
- _dns_openstack_get_records() {
- if ! _records=$(openstack recordset show -c records -f value "$_zone_id" "$fulldomain."); then
- _err "Failed to get records"
- return 1
- fi
- return 0
- }
- _dns_openstack_get_recordset() {
- if ! _recordset_id=$(openstack recordset list -c id -f value --name "$fulldomain." "$_zone_id"); then
- _err "Failed to get recordset"
- return 1
- fi
- return 0
- }
- _dns_openstack_check_setup() {
- if ! _exists openstack; then
- _err "OpenStack client not found"
- return 1
- fi
- }
- _dns_openstack_credentials() {
- _debug "Check OpenStack credentials"
- # If we have OS_AUTH_URL already set in the environment, then assume we want
- # to use those, otherwise use stored credentials
- if [ -n "$OS_AUTH_URL" ]; then
- _debug "OS_AUTH_URL env var found, using environment"
- else
- _debug "OS_AUTH_URL not found, loading stored credentials"
- OS_AUTH_URL="${OS_AUTH_URL:-$(_readaccountconf_mutable OS_AUTH_URL)}"
- OS_IDENTITY_API_VERSION="${OS_IDENTITY_API_VERSION:-$(_readaccountconf_mutable OS_IDENTITY_API_VERSION)}"
- OS_AUTH_TYPE="${OS_AUTH_TYPE:-$(_readaccountconf_mutable OS_AUTH_TYPE)}"
- OS_APPLICATION_CREDENTIAL_ID="${OS_APPLICATION_CREDENTIAL_ID:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID)}"
- OS_APPLICATION_CREDENTIAL_SECRET="${OS_APPLICATION_CREDENTIAL_SECRET:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET)}"
- OS_USERNAME="${OS_USERNAME:-$(_readaccountconf_mutable OS_USERNAME)}"
- OS_PASSWORD="${OS_PASSWORD:-$(_readaccountconf_mutable OS_PASSWORD)}"
- OS_PROJECT_NAME="${OS_PROJECT_NAME:-$(_readaccountconf_mutable OS_PROJECT_NAME)}"
- OS_PROJECT_ID="${OS_PROJECT_ID:-$(_readaccountconf_mutable OS_PROJECT_ID)}"
- OS_USER_DOMAIN_NAME="${OS_USER_DOMAIN_NAME:-$(_readaccountconf_mutable OS_USER_DOMAIN_NAME)}"
- OS_USER_DOMAIN_ID="${OS_USER_DOMAIN_ID:-$(_readaccountconf_mutable OS_USER_DOMAIN_ID)}"
- OS_PROJECT_DOMAIN_NAME="${OS_PROJECT_DOMAIN_NAME:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_NAME)}"
- OS_PROJECT_DOMAIN_ID="${OS_PROJECT_DOMAIN_ID:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_ID)}"
- fi
- # Check each var and either save or clear it depending on whether its set.
- # The helps us clear out old vars in the case where a user may want
- # to switch between password and app creds
- _debug "OS_AUTH_URL" "$OS_AUTH_URL"
- if [ -n "$OS_AUTH_URL" ]; then
- export OS_AUTH_URL
- _saveaccountconf_mutable OS_AUTH_URL "$OS_AUTH_URL"
- else
- unset OS_AUTH_URL
- _clearaccountconf SAVED_OS_AUTH_URL
- fi
- _debug "OS_IDENTITY_API_VERSION" "$OS_IDENTITY_API_VERSION"
- if [ -n "$OS_IDENTITY_API_VERSION" ]; then
- export OS_IDENTITY_API_VERSION
- _saveaccountconf_mutable OS_IDENTITY_API_VERSION "$OS_IDENTITY_API_VERSION"
- else
- unset OS_IDENTITY_API_VERSION
- _clearaccountconf SAVED_OS_IDENTITY_API_VERSION
- fi
- _debug "OS_AUTH_TYPE" "$OS_AUTH_TYPE"
- if [ -n "$OS_AUTH_TYPE" ]; then
- export OS_AUTH_TYPE
- _saveaccountconf_mutable OS_AUTH_TYPE "$OS_AUTH_TYPE"
- else
- unset OS_AUTH_TYPE
- _clearaccountconf SAVED_OS_AUTH_TYPE
- fi
- _debug "OS_APPLICATION_CREDENTIAL_ID" "$OS_APPLICATION_CREDENTIAL_ID"
- if [ -n "$OS_APPLICATION_CREDENTIAL_ID" ]; then
- export OS_APPLICATION_CREDENTIAL_ID
- _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID "$OS_APPLICATION_CREDENTIAL_ID"
- else
- unset OS_APPLICATION_CREDENTIAL_ID
- _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_ID
- fi
- _secure_debug "OS_APPLICATION_CREDENTIAL_SECRET" "$OS_APPLICATION_CREDENTIAL_SECRET"
- if [ -n "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
- export OS_APPLICATION_CREDENTIAL_SECRET
- _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET "$OS_APPLICATION_CREDENTIAL_SECRET"
- else
- unset OS_APPLICATION_CREDENTIAL_SECRET
- _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_SECRET
- fi
- _debug "OS_USERNAME" "$OS_USERNAME"
- if [ -n "$OS_USERNAME" ]; then
- export OS_USERNAME
- _saveaccountconf_mutable OS_USERNAME "$OS_USERNAME"
- else
- unset OS_USERNAME
- _clearaccountconf SAVED_OS_USERNAME
- fi
- _secure_debug "OS_PASSWORD" "$OS_PASSWORD"
- if [ -n "$OS_PASSWORD" ]; then
- export OS_PASSWORD
- _saveaccountconf_mutable OS_PASSWORD "$OS_PASSWORD"
- else
- unset OS_PASSWORD
- _clearaccountconf SAVED_OS_PASSWORD
- fi
- _debug "OS_PROJECT_NAME" "$OS_PROJECT_NAME"
- if [ -n "$OS_PROJECT_NAME" ]; then
- export OS_PROJECT_NAME
- _saveaccountconf_mutable OS_PROJECT_NAME "$OS_PROJECT_NAME"
- else
- unset OS_PROJECT_NAME
- _clearaccountconf SAVED_OS_PROJECT_NAME
- fi
- _debug "OS_PROJECT_ID" "$OS_PROJECT_ID"
- if [ -n "$OS_PROJECT_ID" ]; then
- export OS_PROJECT_ID
- _saveaccountconf_mutable OS_PROJECT_ID "$OS_PROJECT_ID"
- else
- unset OS_PROJECT_ID
- _clearaccountconf SAVED_OS_PROJECT_ID
- fi
- _debug "OS_USER_DOMAIN_NAME" "$OS_USER_DOMAIN_NAME"
- if [ -n "$OS_USER_DOMAIN_NAME" ]; then
- export OS_USER_DOMAIN_NAME
- _saveaccountconf_mutable OS_USER_DOMAIN_NAME "$OS_USER_DOMAIN_NAME"
- else
- unset OS_USER_DOMAIN_NAME
- _clearaccountconf SAVED_OS_USER_DOMAIN_NAME
- fi
- _debug "OS_USER_DOMAIN_ID" "$OS_USER_DOMAIN_ID"
- if [ -n "$OS_USER_DOMAIN_ID" ]; then
- export OS_USER_DOMAIN_ID
- _saveaccountconf_mutable OS_USER_DOMAIN_ID "$OS_USER_DOMAIN_ID"
- else
- unset OS_USER_DOMAIN_ID
- _clearaccountconf SAVED_OS_USER_DOMAIN_ID
- fi
- _debug "OS_PROJECT_DOMAIN_NAME" "$OS_PROJECT_DOMAIN_NAME"
- if [ -n "$OS_PROJECT_DOMAIN_NAME" ]; then
- export OS_PROJECT_DOMAIN_NAME
- _saveaccountconf_mutable OS_PROJECT_DOMAIN_NAME "$OS_PROJECT_DOMAIN_NAME"
- else
- unset OS_PROJECT_DOMAIN_NAME
- _clearaccountconf SAVED_OS_PROJECT_DOMAIN_NAME
- fi
- _debug "OS_PROJECT_DOMAIN_ID" "$OS_PROJECT_DOMAIN_ID"
- if [ -n "$OS_PROJECT_DOMAIN_ID" ]; then
- export OS_PROJECT_DOMAIN_ID
- _saveaccountconf_mutable OS_PROJECT_DOMAIN_ID "$OS_PROJECT_DOMAIN_ID"
- else
- unset OS_PROJECT_DOMAIN_ID
- _clearaccountconf SAVED_OS_PROJECT_DOMAIN_ID
- fi
- if [ "$OS_AUTH_TYPE" = "v3applicationcredential" ]; then
- # Application Credential auth
- if [ -z "$OS_APPLICATION_CREDENTIAL_ID" ] || [ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then
- _err "When using OpenStack application credentials, OS_APPLICATION_CREDENTIAL_ID"
- _err "and OS_APPLICATION_CREDENTIAL_SECRET must be set."
- _err "Please check your credentials and try again."
- return 1
- fi
- else
- # Password auth
- if [ -z "$OS_USERNAME" ] || [ -z "$OS_PASSWORD" ]; then
- _err "OpenStack username or password not found."
- _err "Please check your credentials and try again."
- return 1
- fi
- if [ -z "$OS_PROJECT_NAME" ] && [ -z "$OS_PROJECT_ID" ]; then
- _err "When using password authentication, OS_PROJECT_NAME or"
- _err "OS_PROJECT_ID must be set."
- _err "Please check your credentials and try again."
- return 1
- fi
- fi
- return 0
- }
|