From d344051cd06d78e574c947499eb95427393c6db7 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Nascimento Date: Fri, 31 Mar 2017 19:29:21 +0000 Subject: [PATCH 1/7] Add dnsapi integration for IBM Bluemix (formerly SoftLayer) --- dnsapi/dns_bluemix.sh | 195 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100755 dnsapi/dns_bluemix.sh diff --git a/dnsapi/dns_bluemix.sh b/dnsapi/dns_bluemix.sh new file mode 100755 index 00000000..d93d5b14 --- /dev/null +++ b/dnsapi/dns_bluemix.sh @@ -0,0 +1,195 @@ +#!/usr/bin/env sh +# +# DNS Integration for IBM Bluemix (formerly SoftLayer) +# +# Author: luizgn +# Based on sample from Neilpang +# Report Bugs here: https://github.com/Neilpang/acme.sh +# +######## Public functions ##################### + +domainId= +domain= +host= +recordId= + +dns_bluemix_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Attempting to add ${fulldomain} with ${txtvalue} into Bluemix's DNS." + + # Curl is required + if ! type curl >/dev/null; then + _err "curl missing. Please isntall curl" + return 1 + fi + + # BLUEMIX_USER is required + if [[ "${BLUEMIX_USER}" == "" ]]; then + _err "Environment variable BLUEMIX_USER not defined" + return 1 + fi + + # BLUEMIX_KEY is required + if [[ "${BLUEMIX_KEY}" == "" ]]; then + _err "Environment variable BLUEMIX_KEY not defined" + return 1 + fi + + # Get right domain and domain id + getDomain ${fulldomain} + + # Did we find domain? + if [[ "${domain}" == "" ]]; then + return 1 + fi + + # Check if this DNS entry already exists + getRecordId "${domainId}" "${host}" + + if [[ "${recordId}" == "" ]]; then + # Create record if it doesn't exist + createTxtRecord "${domainId}" "${host}" "${txtvalue}" + else + # Update Record if it already exists + updateTxtRecord "${recordId}" "${txtvalue}" + fi + + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_bluemix_rm() { + fulldomain=$1 + + _info "Attempting to delete ${fulldomain} from Bluemix" + + # Curl is required + if ! type curl >/dev/null; then + _err "curl missing. Please isntall curl" + return 1 + fi + + # BLUEMIX_USER is required + if [[ "${BLUEMIX_USER}" == "" ]]; then + _err "Environment variable BLUEMIX_USER not defined" + return 1 + fi + + # BLUEMIX_KEY is required + if [[ "${BLUEMIX_KEY}" == "" ]]; then + _err "Environment variable BLUEMIX_KEY not defined" + return 1 + fi + + # Get Domain ID + getDomain ${fulldomain} + + if [[ "${domain}" == "" ]]; then + return 1 + fi + + # Get DNS entry in this Domain + getRecordId "${domainId}" "${host}" + + if [[ "${recordId}" == "" ]]; then + _info "recordId for ${fulldomain} not found." + return 1 + fi + + # Remove record + deleteRecordId "${recordId}" + + return 0 + +} + +#################### Private functions below ################################## + +function getDomain { + fulldomain=$1 + + output=$(curl -s -X GET "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Account/getDomains") + + if echo "${output}" | grep '"error":"Access Denied. "' >/dev/null; then + _err "Access Denied, check BLUEMIX_USER and BLUEMIX_KEY environment variables. Details: ${output}" + return 1 + fi + + for domain_item in $(echo "${output}" | awk 'BEGIN{RS=","}/"name"/' | cut -f4 -d'"'); do + if echo "${fulldomain}" | grep "${domain_item}$" >/dev/null; then + domain="${domain_item}" + break + fi + done + + if [[ "${domain}" == "" ]]; then + _err "Domain for ${fulldomain} was not found in this Bluemix account" + return 1 + fi + + domainId=$(echo "${output}" | awk -v DOMAIN=${domain} 'BEGIN{RS=",";FS=":"}{if($1~"\"id\""){id=$2}else if($1~"\"name\""){split($2,d,"\"");domain=d[2];} if($0~/\}$/ && domain==DOMAIN){print id}}') + + host=$(echo "${fulldomain}" | sed "s/\.${domain}\$//g") + + _debug "Host is ${host}, domain is ${domain} and domain id is ${domainId}" + +} + +function getRecordId { + domainId=$1 + host=$2 + + output=$(curl -s -X GET "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Dns_Domain/${domainId}/getResourceRecords") + + recordId=$(echo "${output}" | awk -v HOST=${host} 'BEGIN{RS=",";FS=":"}{if($1=="\"host\""){host=$2}else if($1=="\"id\""){id=$2} if($0~/[\}|\]]$/ && host==("\"" HOST "\"")){print id}}') + + _debug "RecordId is ${recordId}" + +} + +function createTxtRecord { + domainId=$1 + host=$2 + txtvalue=$3 + + output=$(curl -s -X POST -d "{\"parameters\":[{\"host\":\"${host}\",\"data\":\"${txtvalue}\",\"ttl\":\"900\",\"type\":\"txt\",\"domainId\":\"${domainId}\"}]}" \ + "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Dns_Domain_ResourceRecord") + + if echo "${output}" | grep '^\{"error"' >/dev/null; then + _err "Error adding ${fulldomain} in Bluemix's DNS. Details: ${output}" + else + _info "${fulldomain} added into Bluemix's DNS." + _debug ${output} + fi +} + +function updateTxtRecord { + recordId=$1 + txtvalue=$2 + + output=$(curl -s -X PUT -d "{\"parameters\":[{\"data\":\"${txtvalue}\"}]}" \ + "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Dns_Domain_ResourceRecord/${recordId}") + + if echo "${output}" | grep '^\{"error"' >/dev/null; then + _err "Error adding ${fulldomain} in Bluemix's DNS. Details: ${output}" + else + _info "${fulldomain} updated in Bluemix's DNS." + fi +} + +function deleteRecordId { + recordId=$1 + + output=$(curl -s -X DELETE "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Dns_Domain_ResourceRecord/${recordId}") + + if [[ "${output}" == "true" ]]; then + _info "${fulldomain} deleted from Bluemix's DNS." + else + _err "Error deleting ${fulldomain}. Details: ${output}." + fi +} + From 7113e1fa8238f80a0db420270f48654fb79a668e Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Nascimento Date: Fri, 31 Mar 2017 19:40:32 +0000 Subject: [PATCH 2/7] Add dnsapi integration for IBM Bluemix (formerly SoftLayer) --- README.md | 1 + dnsapi/README.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index 7a79bed4..c54f3c8a 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,7 @@ You don't have to do anything manually! 1. DigitalOcean API (native) 1. ClouDNS.net API 1. Infoblox NIOS API (https://www.infoblox.com/) +1. IBM Bluemix API (formerly SoftLayer) **More APIs coming soon...** diff --git a/dnsapi/README.md b/dnsapi/README.md index 9eb77915..b2746d87 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -438,6 +438,20 @@ acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com Note: This script will automatically create and delete the ephemeral txt record. The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. +## 23. Use IBM Bluemix API (formerly SoftLayer) + +First you need to create/obtain API credentials on your IBM Bluemix account. + +``` +export BLUEMIX_USER="" +export BLUEMIX_KEY="" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_bluemix -d example.com -d www.example.com +``` + # Use custom API If your API is not supported yet, you can write your own DNS API. From c0d63501e0aa3baaf583ef3d7eeebac5e69358b2 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Nascimento Date: Fri, 31 Mar 2017 19:45:17 +0000 Subject: [PATCH 3/7] Add dnsapi integration for IBM Bluemix (formerly SoftLayer) --- dnsapi/dns_bluemix.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsapi/dns_bluemix.sh b/dnsapi/dns_bluemix.sh index d93d5b14..ee2c173f 100755 --- a/dnsapi/dns_bluemix.sh +++ b/dnsapi/dns_bluemix.sh @@ -4,7 +4,7 @@ # # Author: luizgn # Based on sample from Neilpang -# Report Bugs here: https://github.com/Neilpang/acme.sh +# Report Bugs here: https://github.com/luizgn/acme.sh # ######## Public functions ##################### From 7f5082330b55de4000f8accfc398f527e86fb3c8 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Nascimento Date: Sun, 2 Apr 2017 11:22:38 +0000 Subject: [PATCH 4/7] just more readable script --- dnsapi/dns_bluemix.sh | 93 ++++++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/dnsapi/dns_bluemix.sh b/dnsapi/dns_bluemix.sh index ee2c173f..8d8bc545 100755 --- a/dnsapi/dns_bluemix.sh +++ b/dnsapi/dns_bluemix.sh @@ -8,6 +8,7 @@ # ######## Public functions ##################### +BLUEMIX_API_URL="https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3" domainId= domain= host= @@ -26,13 +27,13 @@ dns_bluemix_add() { fi # BLUEMIX_USER is required - if [[ "${BLUEMIX_USER}" == "" ]]; then + if [[ -z "${BLUEMIX_USER}" ]]; then _err "Environment variable BLUEMIX_USER not defined" return 1 fi # BLUEMIX_KEY is required - if [[ "${BLUEMIX_KEY}" == "" ]]; then + if [[ -z "${BLUEMIX_KEY}" ]]; then _err "Environment variable BLUEMIX_KEY not defined" return 1 fi @@ -41,14 +42,14 @@ dns_bluemix_add() { getDomain ${fulldomain} # Did we find domain? - if [[ "${domain}" == "" ]]; then + if [[ -z "${domain}" ]]; then return 1 fi # Check if this DNS entry already exists getRecordId "${domainId}" "${host}" - if [[ "${recordId}" == "" ]]; then + if [[ -z "${recordId}" ]]; then # Create record if it doesn't exist createTxtRecord "${domainId}" "${host}" "${txtvalue}" else @@ -74,13 +75,13 @@ dns_bluemix_rm() { fi # BLUEMIX_USER is required - if [[ "${BLUEMIX_USER}" == "" ]]; then + if [[ -z "${BLUEMIX_USER}" ]]; then _err "Environment variable BLUEMIX_USER not defined" return 1 fi # BLUEMIX_KEY is required - if [[ "${BLUEMIX_KEY}" == "" ]]; then + if [[ -z "${BLUEMIX_KEY}" ]]; then _err "Environment variable BLUEMIX_KEY not defined" return 1 fi @@ -88,14 +89,14 @@ dns_bluemix_rm() { # Get Domain ID getDomain ${fulldomain} - if [[ "${domain}" == "" ]]; then + if [[ -z "${domain}" ]]; then return 1 fi # Get DNS entry in this Domain getRecordId "${domainId}" "${host}" - if [[ "${recordId}" == "" ]]; then + if [[ -z "${recordId}" ]]; then _info "recordId for ${fulldomain} not found." return 1 fi @@ -112,26 +113,43 @@ dns_bluemix_rm() { function getDomain { fulldomain=$1 - output=$(curl -s -X GET "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Account/getDomains") + output=$(curl -s -X GET "${BLUEMIX_API_URL}/SoftLayer_Account/getDomains") - if echo "${output}" | grep '"error":"Access Denied. "' >/dev/null; then + if [[ "${output}" =~ '"error":"Access Denied. "' ]]; then _err "Access Denied, check BLUEMIX_USER and BLUEMIX_KEY environment variables. Details: ${output}" return 1 fi for domain_item in $(echo "${output}" | awk 'BEGIN{RS=","}/"name"/' | cut -f4 -d'"'); do - if echo "${fulldomain}" | grep "${domain_item}$" >/dev/null; then + if [[ "${fulldomain}" =~ ${domain_item}$ ]]; then domain="${domain_item}" break fi done - if [[ "${domain}" == "" ]]; then + if [[ -z "${domain}" ]]; then _err "Domain for ${fulldomain} was not found in this Bluemix account" return 1 fi - domainId=$(echo "${output}" | awk -v DOMAIN=${domain} 'BEGIN{RS=",";FS=":"}{if($1~"\"id\""){id=$2}else if($1~"\"name\""){split($2,d,"\"");domain=d[2];} if($0~/\}$/ && domain==DOMAIN){print id}}') + domainId=$(echo "${output}" | \ + awk -v DOMAIN=${domain} ' + BEGIN { + RS=","; + FS=":"; + } + { + if($1~"\"id\"") { + id=$2; + } else if($1~"\"name\"") { + split($2,d,"\""); + domain=d[2]; + } + if($0~/\}$/ && domain==DOMAIN) { + print id; + } + } + ') host=$(echo "${fulldomain}" | sed "s/\.${domain}\$//g") @@ -143,9 +161,25 @@ function getRecordId { domainId=$1 host=$2 - output=$(curl -s -X GET "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Dns_Domain/${domainId}/getResourceRecords") - - recordId=$(echo "${output}" | awk -v HOST=${host} 'BEGIN{RS=",";FS=":"}{if($1=="\"host\""){host=$2}else if($1=="\"id\""){id=$2} if($0~/[\}|\]]$/ && host==("\"" HOST "\"")){print id}}') + output=$(curl -s -X GET "${BLUEMIX_API_URL}/SoftLayer_Dns_Domain/${domainId}/getResourceRecords") + + recordId=$(echo "${output}" | \ + awk -v HOST=${host} ' + BEGIN { + RS=","; + FS=":"; + } + { + if($1=="\"host\"") { + host=$2; + } else if($1=="\"id\"") { + id=$2; + } + if($0~/[\}|\]]$/ && host==("\"" HOST "\"")) { + print id; + } + } + ') _debug "RecordId is ${recordId}" @@ -156,14 +190,15 @@ function createTxtRecord { host=$2 txtvalue=$3 - output=$(curl -s -X POST -d "{\"parameters\":[{\"host\":\"${host}\",\"data\":\"${txtvalue}\",\"ttl\":\"900\",\"type\":\"txt\",\"domainId\":\"${domainId}\"}]}" \ - "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Dns_Domain_ResourceRecord") + payload="{\"parameters\":[{\"host\":\"${host}\",\"data\":\"${txtvalue}\",\"ttl\":\"900\",\"type\":\"txt\",\"domainId\":\"${domainId}\"}]}" + output=$(curl -s -X POST -d "${payload}" "${BLUEMIX_API_URL}/SoftLayer_Dns_Domain_ResourceRecord") + rc=$? - if echo "${output}" | grep '^\{"error"' >/dev/null; then - _err "Error adding ${fulldomain} in Bluemix's DNS. Details: ${output}" - else + if [[ "${rc}" == "0" && "${output}" =~ \"host\":\"${host}\" ]]; then _info "${fulldomain} added into Bluemix's DNS." _debug ${output} + else + _err "Error adding ${fulldomain} in Bluemix's DNS. Details: ${output}" fi } @@ -171,22 +206,24 @@ function updateTxtRecord { recordId=$1 txtvalue=$2 - output=$(curl -s -X PUT -d "{\"parameters\":[{\"data\":\"${txtvalue}\"}]}" \ - "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Dns_Domain_ResourceRecord/${recordId}") + payload="{\"parameters\":[{\"data\":\"${txtvalue}\"}]}" + output=$(curl -s -X PUT -d "${payload}" "${BLUEMIX_API_URL}/SoftLayer_Dns_Domain_ResourceRecord/${recordId}") + rc=$? - if echo "${output}" | grep '^\{"error"' >/dev/null; then - _err "Error adding ${fulldomain} in Bluemix's DNS. Details: ${output}" - else + if [[ "${rc}" == "0" && "${output}" == "true" ]]; then _info "${fulldomain} updated in Bluemix's DNS." + else + _err "Error adding ${fulldomain} in Bluemix's DNS. Details: ${output}" fi } function deleteRecordId { recordId=$1 - output=$(curl -s -X DELETE "https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3/SoftLayer_Dns_Domain_ResourceRecord/${recordId}") + output=$(curl -s -X DELETE "${BLUEMIX_API_URL}/SoftLayer_Dns_Domain_ResourceRecord/${recordId}") + rc=$? - if [[ "${output}" == "true" ]]; then + if [[ "${rc}" == "0" && "${output}" == "true" ]]; then _info "${fulldomain} deleted from Bluemix's DNS." else _err "Error deleting ${fulldomain}. Details: ${output}." From cfdb1087e018f71a12987f61d5b2e48f6e891365 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Nascimento Date: Wed, 17 May 2017 20:44:28 +0000 Subject: [PATCH 5/7] Changes required by Neil --- README.md | 458 +++++++++++++++++++++++++++++++++++ dnsapi/README.md.1 | 541 ++++++++++++++++++++++++++++++++++++++++++ dnsapi/dns_bluemix.sh | 212 +++++++++++++++++ 3 files changed, 1211 insertions(+) create mode 100644 README.md create mode 100644 dnsapi/README.md.1 create mode 100755 dnsapi/dns_bluemix.sh diff --git a/README.md b/README.md new file mode 100644 index 00000000..b6a900c9 --- /dev/null +++ b/README.md @@ -0,0 +1,458 @@ +# An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh) + +[![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +- An ACME protocol client written purely in Shell (Unix shell) language. +- Full ACME protocol implementation. +- Simple, powerful and very easy to use. You only need 3 minutes to learn it. +- Bash, dash and sh compatible. +- Simplest shell script for Let's Encrypt free certificate client. +- Purely written in Shell with no dependencies on python or the official Let's Encrypt client. +- Just one script to issue, renew and install your certificates automatically. +- DOES NOT require `root/sudoer` access. +- Docker friendly +- IPv6 support + +It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt. + +Wiki: https://github.com/Neilpang/acme.sh/wiki + +For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/Neilpang/acme.sh/wiki/Run-acme.sh-in-docker) + +Twitter: [@neilpangxa](https://twitter.com/neilpangxa) + + +# [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E) + +# Who are using **acme.sh** +- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/) +- [ruby-china.org](https://ruby-china.org/topics/31983) +- [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer)) +- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89) +- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt) +- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty) +- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709) +- [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html) +- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297) +- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/) +- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient) +- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials) + +# Tested OS + +| NO | Status| Platform| +|----|-------|---------| +|1|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/ubuntu-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu +|2|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/debian-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian +|3|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/centos-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS +|4|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/windows-cygwin.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included) +|5|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/freebsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD +|6|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/pfsense.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense +|7|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/opensuse-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE +|8|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/alpine-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Alpine Linux (with curl) +|9|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/base-archlinux.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Archlinux +|10|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/fedora-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|fedora +|11|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/kalilinux-kali-linux-docker.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux +|12|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/oraclelinux-latest.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux +|13|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/proxmox.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh +|14|-----| Cloud Linux https://github.com/Neilpang/le/issues/111 +|15|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/openbsd.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD +|16|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/mageia.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia +|17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT) +|18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris +|19|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux +|20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX + +For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest): + +https://github.com/Neilpang/acmetest + + +# Supported modes + +- Webroot mode +- Standalone mode +- Apache mode +- Nginx mode ( Beta ) +- DNS mode +- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode) + + +# 1. How to install + +### 1. Install online + +Check this project: https://github.com/Neilpang/get.acme.sh + +```bash +curl https://get.acme.sh | sh +``` + +Or: + +```bash +wget -O - https://get.acme.sh | sh +``` + + +### 2. Or, Install from git + +Clone this project and launch installation: + +```bash +git clone https://github.com/Neilpang/acme.sh.git +cd ./acme.sh +./acme.sh --install +``` + +You `don't have to be root` then, although `it is recommended`. + +Advanced Installation: https://github.com/Neilpang/acme.sh/wiki/How-to-install + +The installer will perform 3 actions: + +1. Create and copy `acme.sh` to your home dir (`$HOME`): `~/.acme.sh/`. +All certs will be placed in this folder too. +2. Create alias for: `acme.sh=~/.acme.sh/acme.sh`. +3. Create daily cron job to check and renew the certs if needed. + +Cron entry example: + +```bash +0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null +``` + +After the installation, you must close the current terminal and reopen it to make the alias take effect. + +Ok, you are ready to issue certs now. + +Show help message: + +``` +root@v1:~# acme.sh -h +``` + +# 2. Just issue a cert + +**Example 1:** Single domain. + +```bash +acme.sh --issue -d example.com -w /home/wwwroot/example.com +``` + +or: + +```bash +acme.sh --issue -d example.com -w /home/username/public_html +``` + +or: + +```bash +acme.sh --issue -d example.com -w /var/www/html +``` + +**Example 2:** Multiple domains in the same cert. + +```bash +acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com +``` + +The parameter `/home/wwwroot/example.com` or `/home/username/public_html` or `/var/www/html` is the web root folder where you host your website files. You **MUST** have `write access` to this folder. + +Second argument **"example.com"** is the main domain you want to issue the cert for. +You must have at least one domain there. + +You must point and bind all the domains to the same webroot dir: `/home/wwwroot/example.com`. + +Generated/issued certs will be placed in `~/.acme.sh/example.com/` + +The issued cert will be renewed automatically every **60** days. + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + + +# 3. Install the issued cert to Apache/Nginx etc. + +After you issue a cert, you probably want to install/copy the cert to your Apache/Nginx or other servers. +You **MUST** use this command to copy the certs to the target files, **DO NOT** use the certs files in **~/.acme.sh/** folder, they are for internal use only, the folder structure may change in the future. + +**Apache** example: +```bash +acme.sh --install-cert -d example.com \ +--cert-file /path/to/certfile/in/apache/cert.pem \ +--key-file /path/to/keyfile/in/apache/key.pem \ +--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \ +--reloadcmd "service apache2 force-reload" +``` + +**Nginx** example: +```bash +acme.sh --install-cert -d example.com \ +--key-file /path/to/keyfile/in/nginx/key.pem \ +--fullchain-file /path/to/fullchain/nginx/cert.pem \ +--reloadcmd "service nginx force-reload" +``` + +Only the domain is required, all the other parameters are optional. + +The ownership and permission info of existing files are preserved. You may want to precreate the files to have defined ownership and permission. + +Install/copy the issued cert/key to the production Apache or Nginx path. + +The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the Apache/Nginx service will be restarted automatically by the command: `service apache2 restart` or `service nginx restart`. + + +# 4. Use Standalone server to issue cert + +**(requires you to be root/sudoer or have permission to listen on port 80 (TCP))** + +Port `80` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. + +```bash +acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com +``` + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + + +# 5. Use Standalone TLS server to issue cert + +**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))** + +acme.sh supports `tls-sni-01` validation. + +Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. + +```bash +acme.sh --issue --tls -d example.com -d www.example.com -d cp.example.com +``` + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + + +# 6. Use Apache mode + +**(requires you to be root/sudoer, since it is required to interact with Apache server)** + +If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`. + +Particularly, if you are running an Apache server, you should use Apache mode instead. This mode doesn't write any files to your web root folder. + +Just set string "apache" as the second argument and it will force use of apache plugin automatically. + +``` +acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com +``` + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + +# 7. Use Nginx mode + +**(requires you to be root/sudoer, since it is required to interact with Nginx server)** + +If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`. + +Particularly, if you are running an nginx server, you can use nginx mode instead. This mode doesn't write any files to your web root folder. + +Just set string "nginx" as the second argument. + +It will configure nginx server automatically to verify the domain and then restore the nginx config to the original version. + +So, the config is not changed. + +``` +acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com +``` + +More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert + +# 8. Use DNS mode: + +Support the `dns-01` challenge. + +```bash +acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com +``` + +You should get an output like below: + +``` +Add the following txt record: +Domain:_acme-challenge.example.com +Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c + +Add the following txt record: +Domain:_acme-challenge.www.example.com +Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +Please add those txt records to the domains. Waiting for the dns to take effect. +``` + +Then just rerun with `renew` argument: + +```bash +acme.sh --renew -d example.com +``` + +Ok, it's finished. + + +# 9. Automatic DNS API integration + +If your DNS provider supports API access, we can use that API to automatically issue the certs. + +You don't have to do anything manually! + +### Currently acme.sh supports: + +1. CloudFlare.com API +1. DNSPod.cn API +1. CloudXNS.com API +1. GoDaddy.com API +1. PowerDNS.com API +1. OVH, kimsufi, soyoustart and runabove API +1. nsupdate API +1. LuaDNS.com API +1. DNSMadeEasy.com API +1. AWS Route 53 +1. aliyun.com(阿里云) API +1. ISPConfig 3.1 API +1. Alwaysdata.com API +1. Linode.com API +1. FreeDNS (https://freedns.afraid.org/) +1. cyon.ch +1. Domain-Offensive/Resellerinterface/Domainrobot API +1. Gandi LiveDNS API +1. Knot DNS API +1. DigitalOcean API (native) +1. ClouDNS.net API +1. Infoblox NIOS API (https://www.infoblox.com/) +1. VSCALE (https://vscale.io/) +1. Dynu API (https://www.dynu.com) +1. DNSimple API +1. NS1.com API +1. IBM Bluemix API (formerly SoftLayer) + + + +And: + +1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api + (DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.) + + + +**More APIs coming soon...** + +If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project. + +For more details: [How to use DNS API](dnsapi) + + +# 10. Issue ECC certificates + +`Let's Encrypt` can now issue **ECDSA** certificates. + +And we support them too! + +Just set the `length` parameter with a prefix `ec-`. + +For example: + +### Single domain ECC certificate + +```bash +acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256 +``` + +### SAN multi domain ECC certificate + +```bash +acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength ec-256 +``` + +Please look at the last parameter above. + +Valid values are: + +1. **ec-256 (prime256v1, "ECDSA P-256")** +2. **ec-384 (secp384r1, "ECDSA P-384")** +3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)** + + +# 11. How to renew the issued certs + +No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. + +However, you can also force to renew any cert: + +``` +acme.sh --renew -d example.com --force +``` + +or, for ECC cert: + +``` +acme.sh --renew -d example.com --force --ecc +``` + + +# 12. How to upgrade `acme.sh` + +acme.sh is in constant development, so it's strongly recommended to use the latest code. + +You can update acme.sh to the latest code: + +``` +acme.sh --upgrade +``` + +You can also enable auto upgrade: + +``` +acme.sh --upgrade --auto-upgrade +``` + +Then **acme.sh** will be kept up to date automatically. + +Disable auto upgrade: + +``` +acme.sh --upgrade --auto-upgrade 0 +``` + + +# 13. Issue a cert from an existing CSR + +https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR + + +# 14. Under the Hood + +Speak ACME language using shell, directly to "Let's Encrypt". + +TODO: + + +# 15. Acknowledgments + +1. Acme-tiny: https://github.com/diafygi/acme-tiny +2. ACME protocol: https://github.com/ietf-wg-acme/acme +3. Certbot: https://github.com/certbot/certbot + + +# 16. License & Others + +License is GPLv3 + +Please Star and Fork me. + +[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome. + + +# 17. Donate +Your donation makes **acme.sh** better: + +1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/) + +[Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list) diff --git a/dnsapi/README.md.1 b/dnsapi/README.md.1 new file mode 100644 index 00000000..3c771ec9 --- /dev/null +++ b/dnsapi/README.md.1 @@ -0,0 +1,541 @@ +# How to use DNS API + +## 1. Use CloudFlare domain API to automatically issue cert + +First you need to login to your CloudFlare account to get your API key. + +``` +export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +export CF_Email="xxxx@sss.com" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_cf -d example.com -d www.example.com +``` + +The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + +## 2. Use DNSPod.cn domain API to automatically issue cert + +First you need to login to your DNSPod account to get your API Key and ID. + +``` +export DP_Id="1234" +export DP_Key="sADDsdasdgdsf" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_dp -d example.com -d www.example.com +``` + +The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + +## 3. Use CloudXNS.com domain API to automatically issue cert + +First you need to login to your CloudXNS account to get your API Key and Secret. + +``` +export CX_Key="1234" +export CX_Secret="sADDsdasdgdsf" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_cx -d example.com -d www.example.com +``` + +The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + +## 4. Use GoDaddy.com domain API to automatically issue cert + +First you need to login to your GoDaddy account to get your API Key and Secret. + +https://developer.godaddy.com/keys/ + +Please create a Production key, instead of a Test key. + +``` +export GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +export GD_Secret="asdfsdafdsfdsfdsfdsfdsafd" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_gd -d example.com -d www.example.com +``` + +The `GD_Key` and `GD_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + +## 5. Use PowerDNS embedded API to automatically issue cert + +First you need to login to your PowerDNS account to enable the API and set your API-Token in the configuration. + +https://doc.powerdns.com/md/httpapi/README/ + +``` +export PDNS_Url="http://ns.example.com:8081" +export PDNS_ServerId="localhost" +export PDNS_Token="0123456789ABCDEF" +export PDNS_Ttl=60 +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_pdns -d example.com -d www.example.com +``` + +The `PDNS_Url`, `PDNS_ServerId`, `PDNS_Token` and `PDNS_Ttl` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + +## 6. Use OVH/kimsufi/soyoustart/runabove API to automatically issue cert + +https://github.com/Neilpang/acme.sh/wiki/How-to-use-OVH-domain-api + + +## 7. Use nsupdate to automatically issue cert + +First, generate a key for updating the zone +``` +b=$(dnssec-keygen -a hmac-sha512 -b 512 -n USER -K /tmp foo) +cat > /etc/named/keys/update.key < /etc/knot/acme.key +``` + +Include this key in your knot configuration file. + +``` +include: /etc/knot/acme.key +``` + +Next, configure your zone to allow dynamic updates. + +Dynamic updates for the zone are allowed via proper ACL rule with the `update` action. For in-depth instructions, please see [Knot DNS's documentation](https://www.knot-dns.cz/documentation/). + +``` +acl: + - id: acme_acl + address: 192.168.1.0/24 + key: acme_key + action: update + +zone: + - domain: example.com + file: example.com.zone + acl: acme_acl +``` + +Finally, make the DNS server and TSIG Key available to `acme.sh` + +``` +export KNOT_SERVER="dns.example.com" +export KNOT_KEY=`grep \# /etc/knot/acme.key | cut -d' ' -f2` +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_knot -d example.com -d www.example.com +``` + +The `KNOT_SERVER` and `KNOT_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 20. Use DigitalOcean API (native) + +You need to obtain a read and write capable API key from your DigitalOcean account. See: https://www.digitalocean.com/help/api/ + +``` +export DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_dgon -d example.com -d www.example.com +``` + +## 21. Use ClouDNS.net API + +You need to set the HTTP API user ID and password credentials. See: https://www.cloudns.net/wiki/article/42/ + +``` +export CLOUDNS_AUTH_ID=XXXXX +export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com +``` + +## 22. Use Infoblox API + +First you need to create/obtain API credentials on your Infoblox appliance. + +``` +export Infoblox_Creds="username:password" +export Infoblox_Server="ip or fqdn of infoblox appliance" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_infoblox -d example.com -d www.example.com +``` + +Note: This script will automatically create and delete the ephemeral txt record. +The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + + +## 23. Use VSCALE API + +First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/). + +``` +VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_vscale -d example.com -d www.example.com +``` + +## 24. Use Dynu API + +First you need to create/obtain API credentials from your Dynu account. See: https://www.dynu.com/resources/api/documentation + +``` +export Dynu_ClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +export Dynu_Secret="yyyyyyyyyyyyyyyyyyyyyyyyy" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_dynu -d example.com -d www.example.com +``` + +The `Dynu_ClientId` and `Dynu_Secret` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 25. Use DNSimple API + +First you need to login to your DNSimple account and generate a new oauth token. + +https://dnsimple.com/a/{your account id}/account/access_tokens + +Note that this is an _account_ token and not a user token. The account token is +needed to infer the `account_id` used in requests. A user token will not be able +to determine the correct account to use. + +``` +export DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" +``` + +To issue the cert just specify the `dns_dnsimple` API. + +``` +acme.sh --issue --dns dns_dnsimple -d example.com +``` + +The `DNSimple_OAUTH_TOKEN` will be saved in `~/.acme.sh/account.conf` and will +be reused when needed. + +If you have any issues with this integration please report them to +https://github.com/pho3nixf1re/acme.sh/issues. + +## 26. Use NS1.com API + +``` +export NS1_Key="fdmlfsdklmfdkmqsdfk" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_nsone -d example.com -d www.example.com +``` + +## 27. Use IBM Bluemix API (formerly SoftLayer) + +First you need to create/obtain API credentials on your IBM Bluemix account. + +``` +export BLUEMIX_USER="" +export BLUEMIX_KEY="" +``` + +Ok, let's issue a cert now: +``` +acme.sh --issue --dns dns_bluemix -d example.com -d www.example.com +``` + +# Use custom API + +If your API is not supported yet, you can write your own DNS API. + +Let's assume you want to name it 'myapi': + +1. Create a bash script named `~/.acme.sh/dns_myapi.sh`, +2. In the script you must have a function named `dns_myapi_add()` which will be called by acme.sh to add the DNS records. +3. Then you can use your API to issue cert like this: + +``` +acme.sh --issue --dns dns_myapi -d example.com -d www.example.com +``` + +For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh) + + +# Use lexicon DNS API + +https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/dnsapi/dns_bluemix.sh b/dnsapi/dns_bluemix.sh new file mode 100755 index 00000000..50f4c6f9 --- /dev/null +++ b/dnsapi/dns_bluemix.sh @@ -0,0 +1,212 @@ +#!/usr/bin/env sh +# +# DNS Integration for IBM Bluemix (formerly SoftLayer) +# +# Author: luizgn +# Based on sample from Neilpang +# Report Bugs here: https://github.com/luizgn/acme.sh +# +######## Public functions ##################### + +BLUEMIX_API_URL="https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3" + +domainId= +domain= +host= +recordId= + +dns_bluemix_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Attempting to add ${fulldomain} with ${txtvalue} into Bluemix's DNS." + + # BLUEMIX_USER is required + if [ -z "${BLUEMIX_USER}" ]; then + _err "Environment variable BLUEMIX_USER not defined" + return 1 + fi + + # BLUEMIX_KEY is required + if [ -z "${BLUEMIX_KEY}" ]; then + _err "Environment variable BLUEMIX_KEY not defined" + return 1 + fi + + # Check BLUEMIX_USER and BLUEMIX_KEY access + if ! hasAccess; then + _err "Error accessing BlueMix API. Check \$BLUEMIX_USER and \$BLUEMIX_KEY and ensure there is access to https://api.softlayer.com/" + return 1 + fi + + # Get right domain and domain id + if ! getDomain ${fulldomain}; then + _err "Domain for ${fulldomain} was not found in this Bluemix account" + return 1 + fi + + # Check if this DNS entry already exists + if getRecordId "${domainId}" "${host}"; then + # Update Record if it already exists + updateTxtRecord "${recordId}" "${txtvalue}" + else + # Create record if it doesn't exist + createTxtRecord "${domainId}" "${host}" "${txtvalue}" + fi + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_bluemix_rm() { + fulldomain=$1 + + _info "Attempting to delete ${fulldomain} from Bluemix" + + # BLUEMIX_USER is required + if [ -z "${BLUEMIX_USER}" ]; then + _err "Environment variable BLUEMIX_USER not defined" + return 1 + fi + + # BLUEMIX_KEY is required + if [ -z "${BLUEMIX_KEY}" ]; then + _err "Environment variable BLUEMIX_KEY not defined" + return 1 + fi + + # Check BLUEMIX_USER and BLUEMIX_KEY access + if ! hasAccess; then + _err "Error accessing BlueMix API. Check \$BLUEMIX_USER and \$BLUEMIX_KEY and ensure there is access to https://api.softlayer.com/" + return 1 + fi + + # Get Domain ID + if ! getDomain ${fulldomain}; then + _err "Domain for ${fulldomain} was not found in this Bluemix account" + return 1 + fi + + # Get DNS entry in this Domain + if getRecordId "${domainId}" "${host}"; then + + # Remove record + deleteRecordId "${recordId}" + + fi + + return 0 + +} + +#################### Private functions below ################################## + +function hasAccess { + response=$(_get "${BLUEMIX_API_URL}/SoftLayer_Account/getDomains") + + if [[ -z "${response}" || "${response}" =~ 'Access Denied' ]]; then + _debug "Code=${code}, Response=${response}" + return 1 + else + return 0 + fi +} + +function getDomain { + fulldomain=$1 + + response=$(_get "${BLUEMIX_API_URL}/SoftLayer_Account/getDomains") + _debug "Code=${code}, Response=${response}" + + for domain_item in $(echo "${response}" | tr , \\n | grep "^\"name\":" | cut -f4 -d'"'); do + if [[ "${fulldomain}" =~ ${domain_item}$ ]]; then + domain="${domain_item}" + break + fi + done + + if [ -z "${domain}" ]; then + return 1 + fi + + domainId=$(echo "${response}" | tr \} \\n | grep "\"name\":\"${domain}\"" | sed -n 's/.*\"id\":\([0-9]*\).*/\1/p') + + host=$(echo "${fulldomain}" | sed "s/\.${domain}\$//g") + + _debug "Host is ${host}, domain is ${domain} and domain id is ${domainId}" + + return 0 +} + +function getRecordId { + domainId=$1 + host=$2 + + response=$(_get "${BLUEMIX_API_URL}/SoftLayer_Dns_Domain/${domainId}/getResourceRecords") + _debug "Code=${code}, Response=${response}" + + recordId=$(echo "${response}" | tr \} \\n | grep "\"host\":\"${host}\"" | sed -n 's/.*\"id\":\([0-9]*\).*/\1/p') + + if [ -z "${recordId}" ]; then + return 1 + else + _debug "RecordId is ${recordId}" + return 0 + fi + +} + +function createTxtRecord { + domainId=$1 + host=$2 + txtvalue=$3 + + payload="{\"parameters\":[{\"host\":\"${host}\",\"data\":\"${txtvalue}\",\"ttl\":\"60\",\"type\":\"txt\",\"domainId\":\"${domainId}\"}]}" + response=$(_post "${payload}" "${BLUEMIX_API_URL}/SoftLayer_Dns_Domain_ResourceRecord" "") + _debug "Code=${code}, Response=${response}" + + if [[ "${response}" =~ \"host\":\"${host}\" ]]; then + _info "${fulldomain} added into Bluemix's DNS." + return 0 + else + _err "Error adding ${fulldomain} in Bluemix's DNS. Details: ${response}" + return 1 + fi + +} + +function updateTxtRecord { + recordId=$1 + txtvalue=$2 + + payload="{\"parameters\":[{\"data\":\"${txtvalue}\"}]}" + response=$(_post "${payload}" "${BLUEMIX_API_URL}/SoftLayer_Dns_Domain_ResourceRecord/${recordId}" "" "PUT") + _debug "Code=${code}, Response=${response}" + + if [ "${response}" == "true" ]; then + _info "${fulldomain} updated in Bluemix's DNS." + return 0 + else + _err "Error adding ${fulldomain} in Bluemix's DNS. Details: ${response}" + return 1 + fi + +} + +function deleteRecordId { + recordId=$1 + + response=$(_post "" "${BLUEMIX_API_URL}/SoftLayer_Dns_Domain_ResourceRecord/${recordId}" "" "DELETE") + _debug "Code=${code}, Response=${response}" + + if [ "${response}" == "true" ]; then + _info "${fulldomain} deleted from Bluemix's DNS." + return 0 + else + _err "Error deleting ${fulldomain}. Details: ${response}." + return 1 + fi + +} + From bf82eafc13a53941374a803c2fcb14d5a0c59e3d Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Nascimento Date: Wed, 17 May 2017 20:46:32 +0000 Subject: [PATCH 6/7] Fixed file name --- dnsapi/{README.md.1 => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dnsapi/{README.md.1 => README.md} (100%) diff --git a/dnsapi/README.md.1 b/dnsapi/README.md similarity index 100% rename from dnsapi/README.md.1 rename to dnsapi/README.md From 531a4f1797ac0918ed4af404ab9caf5aa52a5269 Mon Sep 17 00:00:00 2001 From: Luiz Gustavo Nascimento Date: Wed, 17 May 2017 20:52:36 +0000 Subject: [PATCH 7/7] Added dnsapi support for IBM Bluemix (formerly SoftLayer) --- README.md | 1 - dnsapi/README.md | 1 + dnsapi/dns_bluemix.sh | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6a900c9..e408dfbf 100644 --- a/README.md +++ b/README.md @@ -334,7 +334,6 @@ You don't have to do anything manually! 1. IBM Bluemix API (formerly SoftLayer) - And: 1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api diff --git a/dnsapi/README.md b/dnsapi/README.md index 3c771ec9..2f506789 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -519,6 +519,7 @@ Ok, let's issue a cert now: acme.sh --issue --dns dns_bluemix -d example.com -d www.example.com ``` + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_bluemix.sh b/dnsapi/dns_bluemix.sh index 50f4c6f9..bcec3213 100755 --- a/dnsapi/dns_bluemix.sh +++ b/dnsapi/dns_bluemix.sh @@ -6,7 +6,7 @@ # Based on sample from Neilpang # Report Bugs here: https://github.com/luizgn/acme.sh # -######## Public functions ##################### +#################### Public functions ################################## BLUEMIX_API_URL="https://${BLUEMIX_USER}:${BLUEMIX_KEY}@api.softlayer.com/rest/v3"