Skip to content

Commit

Permalink
Release version 2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarm1964 committed May 9, 2020
1 parent e1932b9 commit 1f58e99
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 52 deletions.
122 changes: 91 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# getcerts.sh

The package `getcerts.sh` is an all-in-one solution to create private keys,
The wrapper `getcerts.sh` is an all-in-one solution to create private keys,
generate a signing request (csr) and obtain certificates from Let's Encrypt
for multiple domains. And, of course, subject alternative names are supported.

Expand All @@ -9,9 +9,9 @@ Furthermore, the script can install (new) certificates and restart the web serve
New certificates can be requested and installed without any downtime. The only
downtime needed, is to activate the (new) certificates.

The package `getcerts.sh` is based upon the excellent work done by Daniel Roesler and Jon Lundi:
The wrapper `getcerts.sh` is based upon the excellent work done by Daniel Roesler and Jon Lundi:

[acme-tiny.py](https://github.com/diafygi/acme-tiny)<br/>
[acme-tiny](https://github.com/diafygi/acme-tiny)<br/>
[conv.py](https://gist.github.com/JonLundy/f25c99ee0770e19dc595)

An option, `--staging`, to use Let's Encrypt's staging directory has been added
Expand Down Expand Up @@ -132,10 +132,11 @@ openssl rsa -in private_key.der -inform der -out keys/letsencrypt-account.key
rm private_key.asn1 private_key.der private_key.json
```

#### Sudo
#### Sudo configuration

If a single purpose user, e.g. `acme`, has been created, it needs a sudo entry
to be able to install the new certificates and to restart the web server.
Create a file in `/etc/sudoers.d`. For example `/etc/sudoers/acme`, with the
Create a file in `/etc/sudoers.d`, for example `/etc/sudoers/acme`, with the
following (or similar) content:

```
Expand Down Expand Up @@ -233,34 +234,87 @@ be configured as follows:
</VirtualHost>
```

#### Cron

Of course, cron can be set up to run this command once per month. Put this
in the crontab for user acme:

```
* * 1 * * getcerts.sh --auto-generate && sudo getcerts.sh --install-certificates
```

### Usage

#### Creating a key

```
getcerts.sh -k
```

This will create a private 4096 bits RSA key which is stored in `keys' directory.

#### Generating a CSR

```
getcerts.sh -c
```

This will create a signing request (CSR) for all configured domains, which are stored
in `certs` directory. The configured subject alternative names are set up in this
signing request.

### Request certificates

```
getcerts.sh -g
```

This will request a new certificate from Let's Encrypt for each configured
domain. These are in fact a chain which will be split up into separate certificates.

#### Install new certificates

```
getcerts.sh -i
```

This will save the currently installed certificates and store the newly created
certificates into the configured system wide location. If all this was successful,
he web server will be restarted. Due to this, it might be essential to run this step
as `root`.

#### General usage information

Running `getcerts.sh --help` as a regular user shows this information:

```
getcerts.sh: usage: getcerts.sh [-h|-u]
or: getcerts.sh [-C]
or: getcerts.sh [-D <tld>] [-H <home>] [-S] [-v] -L|-V|-a|-c|-d|-g|-i|-k|-l|-s]
or: getcerts.sh [-D <tld>] [-F] [-H <home>] [-I] [-m <days>] [-S] [-v] -L|-V|-a|-c|-d|-f|-g|-i|-k|-l|-s]
options:
-C,--config - do some basic configuration verification
-D,--domain <tld> - top level domain to use, default: example.com
-H,--home <home> - home to use, default: /home/acme
-L,--list-csr - list certificate signing request
-S,--staging - use Let's Encrypt staging directory
-V,--verify-csr - verify the certificate signing request
-a,--auto-generate - automagically create a new CSR and request new certificate
-c,--create-csr - create new certificate signing request
-d,--list-domains - list domains
-g,--get-certificates - get new certificates
-h,--help - show this information
-i,--install-certificates - install (new) certificates
-k,--create-key - create a domain key
-l,--list-certificates - list current certificates (default)
-s,--list-sans - list subject alternative names
-u,--usage - show some brief usage information
-v,--verbose - be more verbose
--version - show version
-C,--config - do some basic configuration verification
-D,--domain <tld> - top level domain to use, default: edgar-matzinger.nl
-F,--force - force the request of a new certificate
-H,--home <home> - home to use, default: /home/acme
-I,--info - show informatiopn about installed certificates
-L,--list-csr - list certificate signing request
-S,--staging - use Let's Encrypt staging directory
-V,--verify-csr - verify the certificate signing request
-a,--auto-generate - automagically create a new CSR and request new certificate
-c,--create-csr - create new certificate signing request
-d,--list-domains - list domains
-f,--force - force the request of a new certificate
-g,--get-certificates - get new certificates
-h,--help - show this information
-i,--install-certificates - install (new) certificates
-k,--create-key - create a domain key
-l,--list-certificates - list current certificates (default)
-m,--min-days-left <days> - get a new certificate if validity current one has less than <days> left, default: 30
-s,--list-sans - list subject alternative names
-u,--usage - show some brief usage information
-v,--verbose - be more verbose
--version - show version
options can be specified in any order
```
Expand All @@ -273,13 +327,19 @@ or: getcerts.sh [-C]
or: getcerts.sh [-H <home>] [-i] [-v]
options:
-C,--config - do some basic configuration verification
-H,--home <home> - home to use, default: /home/acme
-h,--help - show this information
-i,--install-certificates - install (new) certificates
-u,--usage - show some brief usage information
-v,--verbose - be more verbose
--version - show version
-C,--config - do some basic configuration verification
-H,--home <home> - home to use, default: /home/acme
-h,--help - show this information
-i,--install-certificates - install (new) certificates
-u,--usage - show some brief usage information
-v,--verbose - be more verbose
--version - show version
options can be specified in any order
```

The easiest way to get new certificates from Let's Encrypt is to run:

```sh
getcerts.sh --auto-generate && sudo getcerts.sh --install-certificates
```
59 changes: 57 additions & 2 deletions bin/getcerts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,55 @@
## @changelog converted from certbot to acme-tiny
##
## @globalstart
## @global{FORCE,-,force the creation of a new certificate if unequal to 0}
## @global{HOMEDIR,-,the location where getcert.sh is installed}
## @global(MINDAYSLEFT,-,a new certificate is requested if current certificate has less than this number of days validity left}
## @global{PROGNAME,-,the name of the script}
## @global{USESTAGING,-,1 if Let's Encrypt's staging directory should be used\, 0 otherwise}
## @global{VERBOSE,-,be more verbose}
## @global{VERSION,-,version}
## @globalend
##
## @exitcodestart
## @exitcode{1,option --${OPTARG} needs an argument (file: bin/getcerts.sh\, line: 321\, 337\, 357)}
## @exitcode{1,option --${_opt} needs an argument (file: bin/getcerts.sh\, line: 317\, 328\, 353)}
## @exitcode{10,${CONFIGDIR}/domain.txt doesn't exist (file: lib/misc.sh\, line: 43)}
## @exitcode{11,please create ${CONFIGDIR}/domain.txt (file: lib/misc.sh\, line: 88)}
## @exitcode{12,${CONFIGDIR}/${DOMAIN}-san.txt doesn't exist (file: lib/misc.sh\, line: 110)}
## @exitcode{13,key creation failed (file: lib/csr.sh\, line: 27)}
## @exitcode{14,no subject alternative names defined (file: lib/csr.sh\, line: 58)}
## @exitcode{15,${CERTDIR}/${DOMAIN}.csr doesn't exist (file: lib/csr.sh\, line: 90)}
## @exitcode{16,${CERTDIR}/${DOMAIN}.csr couldn't be listed (file: lib/csr.sh\, line: 95)}
## @exitcode{17,${CERTDIR}/${DOMAIN}.csr couldn't be listed (file: lib/csr.sh\, line: 101)}
## @exitcode{18,${CERTDIR}/${DOMAIN}.csr doesn't exist (file: lib/csr.sh\, line: 126)}
## @exitcode{19,${CERTDIR}/${DOMAIN}.csr couldn't be verified (file: lib/csr.sh\, line: 132)}
## @exitcode{20,current top level domain certificate has ${daysLeft} days validity left\, not requesting a new certificate (file: lib/certificate.sh\, line: 45)}
## @exitcode{21,couldn't create ${DOMAIN} certificate (file: lib/certificate.sh\, line: 88)}
## @exitcode{22,could create Let's Encrypt cross signed certificate (file: lib/certificate.sh\, line: 91)}
## @exitcode{23,${CERTDIR}/${DOMAIN}.crt doesn't exist (file: lib/certificate.sh\, line: 118)}
## @exitcode{24,${CERTDIR}/${DOMAIN}.crt couldn't be listed (file: lib/certificate.sh\, line: 123)}
## @exitcode{25,${CERTDIR}/${DOMAIN}.crt couldn't be listed (file: lib/certificate.sh\, line: 134)}
## @exitcode{26,${certfile} doesn't exist (file: lib/certificate.sh\, line: 168)}
## @exitcode{27,${certfile} couldn't be listed (file: lib/certificate.sh\, line: 173)}
## @exitcode{28,${certfile} couldn't be listed (file: lib/certificate.sh\, line: 185)}
## @exitcode{29,certificate ${DOMAIN}.crt doesn't exit (file: lib/certificate.sh\, line: 213)}
## @exitcode{30,configuration verification was unsuccessful\, run ${PROGNAME} -C|--config for more information (file: bin/getcerts.sh\, line: 84)}
## @exitcode{30,couldn't save current ${DOMAIN} certificate (file: lib/certificate.sh\, line: 217)}
## @exitcode{31,couldn't remove current Subject Alternative Name certificate ${certfile}.crt (file: lib/certificate.sh\, line: 225)}
## @exitcode{32,couldn't create ${DOMAIN} certificate (file: lib/certificate.sh\, line: 230)}
## @exitcode{33,couldn't create Subject Alternative Name certificate ${certfile}.crt (file: lib/certificate.sh\, line: 235)}
## @exitcode{34,couldn't restart httpd (file: lib/certificate.sh\, line: 239)}
## @exitcodeend
##
#

PROGNAME=${0##*/}
VERBOSE=0
USESTAGING=0
HOMEDIR='/home/acme'
VERSION="2.0"
MINDAYSLEFT=30
FORCE=0

##
## @fn init(number doConfigVerify, string acmehome)
Expand Down Expand Up @@ -191,7 +228,7 @@ function usage
# always show usage...
echo -e "${PROGNAME}: usage: ${PROGNAME} [-h|-u]"
echo -e "or: ${PROGNAME} [-C]"
[[ ${MYID} -ne 0 ]] && echo -e "or: ${PROGNAME} [-D <tld>] [-H <home>] [-S] [-v] -L|-V|-a|-c|-d|-g|-i|-k|-l|-s]"
[[ ${MYID} -ne 0 ]] && echo -e "or: ${PROGNAME} [-D <tld>] [-F] [-H <home>] [-I] [-m <days>] [-S] [-v] -L|-V|-a|-c|-d|-f|-g|-i|-k|-l|-s]"
[[ ${MYID} -eq 0 ]] && echo -e "or: ${PROGNAME} [-H <home>] [-i] [-v]"
if [[ ${exitcode} -eq 2 ]]; then
#
Expand All @@ -202,15 +239,18 @@ function usage
#
# non-root user...
echo -e "\t-D,--domain <tld>\t\t- top level domain to use, default: ${DOMAIN}"
echo -e "\t-F,--force\t\t\t- force the request of a new certificate"
fi
echo -e "\t-H,--home <home>\t\t- home to use, default: ${HOMEDIR}"
if [[ ${MYID} -ne 0 ]]; then
echo -e "\t-I,--info\t\t\t- show informatiopn about installed certificates"
echo -e "\t-L,--list-csr\t\t\t- list certificate signing request"
echo -e "\t-S,--staging\t\t\t- use Let's Encrypt staging directory"
echo -e "\t-V,--verify-csr\t\t\t- verify the certificate signing request"
echo -e "\t-a,--auto-generate\t\t- automagically create a new CSR and request new certificate"
echo -e "\t-c,--create-csr\t\t\t- create new certificate signing request"
echo -e "\t-d,--list-domains\t\t- list domains"
echo -e "\t-f,--force\t\t\t- force the request of a new certificate"
echo -e "\t-g,--get-certificates\t\t- get new certificates"
fi
echo -e "\t-h,--help\t\t\t- show this information"
Expand All @@ -220,6 +260,7 @@ function usage
# non-root user...
echo -e "\t-k,--create-key\t\t\t- create a domain key"
echo -e "\t-l,--list-certificates\t\t- list current certificates (default)"
echo -e "\t-m,--min-days-left <days>\t- get a new certificate if validity current one has less than <days> left, default: ${MINDAYSLEFT}"
echo -e "\t-s,--list-sans\t\t\t- list subject alternative names"
fi
echo -e "\t-u,--usage\t\t\t- show some brief usage information"
Expand Down Expand Up @@ -297,7 +338,7 @@ SINGLEDOMAIN=''

#
# process arguments
while getopts ":CD:H:LSVacdghiklsuv-:" optchar; do
while getopts ":CD:FH:ILSVacdghiklm:suv-:" optchar; do
case "${optchar}" in
-) case "${OPTARG}" in
auto-g*) ACTION=autoCreateAndGetCertificate ;;
Expand All @@ -312,6 +353,7 @@ while getopts ":CD:H:LSVacdghiklsuv-:" optchar; do
(( OPTIND++ ))
[[ -z "${SINGLEDOMAIN}" ]] && usage 1 "option --${OPTARG} needs an argument"
;;
force) FORCE=1 ;;
get-cert*) ACTION=getCertificate ;;
help) usage 2 "" ;;
home=*) export HOMEDIR=${OPTARG##*=}
Expand All @@ -332,11 +374,21 @@ while getopts ":CD:H:LSVacdghiklsuv-:" optchar; do
init 0 "${HOMEDIR}"
getDefaultDomainIfExists
;;
info) ACTION=listInstalledCertificates ;;
install-cert*) ACTION=installCertificates ;;
list-csr) ACTION=listCSR ;;
list-domains) ACTION=listDomains ;;
list-cert*) ACTION=listCertificates ;;
list-sans) ACTION=listSANS ;;
min-days-left=*)
MINDAYSLEFT=${OPTARG##*=}
_opt=${OPTARG%%=${MINDAYSLEFT}}
[[ -z "${MINDAYSLEFT}" ]] && usage 1 "option --${_opt} needs an argument"
;;
min-days-left) MINDAYSLEFT=${!OPTIND}
(( OPTIND++ ))
[[ -z "${MINDAYSLEFT}" ]] && usage 1 "option --${OPTARG} needs an argument"
;;
staging) USESTAGING=1 ;;
usage) usage 1 "" ;;
verbose) (( VERBOSE++ )) ;;
Expand All @@ -346,13 +398,15 @@ while getopts ":CD:H:LSVacdghiklsuv-:" optchar; do
esac;;
C) ACTION=verifyConfig ;;
D) export SINGLEDOMAIN="${OPTARG}" ;;
F) FORCE=1 ;;
H) HOMEDIR="${OPTARG}"

#
# reinitialise settings and get default domain
init 0 "${HOMEDIR}"
getDefaultDomainIfExists
;;
I) ACTION=listInstalledCertificates ;;
L) ACTION=listCSR ;;
S) USESTAGING=1 ;;
V) ACTION=verifyCSR ;;
Expand All @@ -364,6 +418,7 @@ while getopts ":CD:H:LSVacdghiklsuv-:" optchar; do
i) ACTION=installCertificates ;;
k) ACTION=createKey ;;
l) ACTION=listCertificates ;;
m) MINDAYSLEFT=${!OPTIND} ;;
s) ACTION=listSANS ;;
u) usage 1 "" ;;
v) (( VERBOSE++ )) ;;
Expand Down
3 changes: 3 additions & 0 deletions doxygen/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ ALIASES += "global{2} = <tr><td class=\"paramdir\">[\2]</td><td co
ALIASES += "global{3} = <tr><td class=\"paramdir\">[\2]</td><td class=\"paramname\">\1</td><td>\3</td></tr>\n"
ALIASES += "globalstart = @par<b>Global variables</b>\n@parblock\n<table class=\"params\">\n"
ALIASES += "globalend = </table>\n@endparblock\n"
ALIASES += "exitcode{2} = <tr><td class=\"paramdir\"></td><td class=\"paramname\">\1</td><td>\2</td></tr>\n"
ALIASES += "exitcodestart = @par<b>Exit codes</b>\n@parblock\n<table class=\"params\">\n"
ALIASES += "exitcodeend = </table>\n@endparblock\n"

# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
Expand Down
Loading

0 comments on commit 1f58e99

Please sign in to comment.