acmeshell

module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 10, 2019 License: MPL-2.0

README

ACMEShell

An interactive shell designed for ACME client/server developers to use for tests, day to day tasks, and exploring the protocol. ACMEShell Supports both interactive and non-interactive usage.


Build Status GolangCI Go Report Card



asciicast


Warning

ACMEShell is not a shell script based ACME client, it's a shell environment for ACME. If you're looking for a shell script ACME client you should try acme.sh instead.

ACMEShell is designed for developers - not server administrators. Do not use ACMEShell to issue or renew production certificates. Do not write automation around ACMEShell to manage real certificates and keypairs! Instead, use a real ACME client (like Certbot) or a real ACME library (like Lego).

ACMEShell was coded in short bursts of infrequent free time. The code quality is not my best work. Cleanup pull requests are welcome. If something seems strange it's probably because I threw it together in a rush while trying to make progress on my real task (likely debugging Boulder).

Quick-start

  1. Pick an ACMEShell release and download the .tar.gz archive for your architecture (for example Linux_x86_64.tar.gz):

    wget https://github.com/cpu/acmeshell/releases/download/v0.0.1/acmeshell_0.0.1_Linux_x86_64.tar.gz
    
  2. Extract the archive and change into the extracted directory:

    tar xf acmeshell_*.tar.gz
    cd acmeshell*
    
  3. Make the acmeshell program executable:

    chmod +x acmeshell
    
  4. Run the acmeshell program:

    ./acmeshell
    

That's it! You should find yourself in an ACMEShell session with the Let's Encrypt "ACME v2" staging environment ACME server. A new ACME account will have automatically been created for your session. You're ready to go!

Features

  • Convenient interactive shell supporting auto-completion of commands and menu selection of ACME objects.
  • Non-interactive usage suitable for scripts and automated tests.
  • High level commands like newOrder, getAuthz, solve for interacting with an ACME server quickly and easily.
  • Low level commands like sign, post, and get to have fine-grain control over protocol messages to exercise new features or reproduce corner-case bugs.
  • Powerful templating support for convenient manual construction of authenticated protocol messages.
  • Create, save/load and switch between many ACME accounts in one session.
  • Create, save/load, and use named private keys for ACME messages (CSRs, key rollovers, etc).
  • Built-in challenge server for returning HTTP-01 and TLS-ALPN-01 challenge responses (also supports using an external pebble-challtestsrv).
  • Built-in mock DNS server for DNS-01 challenges and directing HTTP-01/TLS-ALPN-01 requests to the built-in challenge server.
  • Supports logging all HTTP requests/responses, JWS objects, and to-be-signed JSON messages to give full protocol visibility.
  • Utility functions for generating CSRs and working with Base64URL encoded data.

The ACME Playset

If you would like to experiment with an end-to-end ACME environment where you can fake DNS entries and issue untrusted test certificates for domains you don't control ACMEShell integrates out of the box with Pebble.

To get started install Docker and Docker Compose and then run the following command in the acmeshell repo:

   docker-compose up

This will start a pebble container configured to use a second pebble-challtestsrv container for DNS.

To connect ACMEShell to the Pebble container and use the pebble-challtestsrv container for challenge responses run:

   acmeshell -pebble -postAsGet=true -challsrv=http://localhost:8055

Usage

Server Options
Directory

The most important option is -directory command line flag. If none is provided ACMEShell will use the Let's Encrypt ACME v2 staging environment server directory address.

ACME Server HTTPS CA Certificate

Many test ACME servers (Pebble included) serve their API over an HTTPS address with a certificate that isn't signed by a root in the system's trusted CA store. You can specify a custom root CA certificate to use to validate the ACME server's HTTPS certificate with the -ca flag.

Pebble Defaults

If you specify -pebble then Pebble defaults are assumed and the -directory address will be https://localhost:14000/dir to match the Pebble default and the -ca flag will be $GOPATH/src/github.com/letsencrypt/pebble/test/certs/pebble.minica.pem. If you do not have Pebble installed in your $GOPATH you may need to download the pebble.minica.pem file from the Pebble repo and specify its location with the -ca flag.

POST-AS-GET

ACMEShell supports using POST-AS-GET to fetch resources, or the legacy unauthenticated GET method. By default ACMEShell uses unauthenticated GETs but this will likely change in the near future.

If you are using Pebble or another ACME server that enforces the use of authenticated POST-AS-GET requests you will want to specify -postASGet=true to make ACMEShell always use POST-AS-GET in higher level commands.

Account Management

ACMEShell supports multiple ACME accounts. One account is considered "active" at a time and is used by the higher level commands.

Command Line Flags

By default without changing any command line flags acmeshell will try to load an active ACME account at startup from acmeshell.account.json in the current directory.

If that file doesn't, ACMEShell will create a new account with the ACME server and save it to acmeshell.account.json to use the next time acmeshell starts.

You can disable acmeshell automatically creating an account if one doesn't exist by using -autoregister=false. In this case if the acmeshell.account.json file doesn't exist acmeshell will still startup but there will be no active account and many commands will not work until one is created with newAccount.

By default no contact address is provided when automatically creating an account at startup. Use -contact=some-email@address.com to set a contact address when creating an auto-registered account.

Creating More Accounts

To create new accounts above and beyond the autoregistered account use the newAccount command.

Usage of newAccount:
  -contacts string
    	Comma separated list of contact emails
  -json string
    	Optional filepath to a JSON save file for the account
  -keyID string
    	Key ID for existing key (empty to generate new key)
  -switch
    	Switch to the new account after creating it (default true)

For example to create and switch to a new ACME account with two contact addresses that will be persisted to /tmp/foo.bar.account.json run:

   newAccount -contacts=foo@example.com,bar@example.com \
      -json=/tmp/foo.bar.account.json \

If you wanted to create the account but not switch to it, add -switch=false.

Listing Accounts

You can list the available accounts with the accounts command:

Usage of accounts:
  -showContact
    	Print ACME account contact info (default true)
  -showID
    	Print ACME account IDs (default true)
Switching Accounts

You can switch the active account with the switchAccount command:

Usage of switchAccount:
  -account int
    	account number to switch to. leave blank to pick interactively (default -1)

The -account index corresponds to the output from accounts.

Save Active Account Data

After creating newOrder's it can be useful to save the active account's state to the -json file that was provided when it was created with newAccount (or the -account file that it was loaded from by acmeshell). To do so use the saveAccount command.

Usage of saveAccount:
  -json string
    	Filepath to a JSON save file for the account. If empty the -account argument is used
Load accounts

To load an account from JSON that isn't present in the accounts output (e.g. because it was perhaps created in a different session) use the loadAccount command:

Usage of loadAccount:
  -switch
    	Switch to the account after loading it (default true)
Key Management

ACMEShell supports managing multiple private keys and giving them human identifiable labels to make it easy to use them for other ACME commands/messages.

Account keys

By default all accounts that are created by ACMEShell get an account private key automatically created for them with a label equal to ID the server gave the account.

For example if my -autoregister account was given the ID "https://localhost:14000/my-account/1" by the ACME server then ACMEShell will have created a private key with the label "https://localhost:14000/my-account/1" with the account private key.

Creating additional keys

Some commands (e.g. finalize, csr) will automatically generate random private keys as required. If you need to control the private key that is used you can create additional private keys and reference them by ID in other commands.

Use the newKey command to create a new private key:

Usage of newKey:
  -id string
    	ID for the new key
  -jwk
    	Print JWK output (default true)
  -path string
    	Path to write PEM private key to
  -pem
    	Print PEM output
Viewing a key

Use the viewKey command to interactively list keys and display the chosen private key's public JWK and Thumbprint.

Load keys

Load an existing private key (in PEM representation) from a file using the loadKey command:

Usage of loadKey:
  -id string
    	ID for the key
Workflow
Interactive and non-interactive

The high level commands let you quickly perform ACME operations without having to manually construct any messages. Most of these commands support two methods of use:

  • if not enough arguments are provided they can be used interactively, letting you choose objects from a menu.
  • if enough arguments are provided to unambiguously perform the operation it will be done non-interactively
Order indexes

Each order created with the newOrder command is assigned an order index to make it easy to reference in other commands. The first order will be index 0, the second 1, and so on. These indexes are account specific. If you change the active account with switchAccount the order indexes will change to be based on the orders that the new account has created.

High level commands
  • newAccount - create an account with the server.
  • getAccount - fetch the active account's details from the server.
  • rollover - change the active account's key to a new key.
  • newOrder - create an order resource.
  • getOrder - fetch an order resource.
  • getAuthz - fetch an authorization resource.
  • getChall - fetch a challenge resource.
  • solve - solve a challenge associated with an authz from an order.
  • poll - poll a resource until its in a specific state.
  • finalize - finalize an order by POSTing a CSR.
  • getCert - get an order's certificate resource.

Here's an example of using the high level commands non-interactively to complete an order issuance:

   newOrder -identifiers=threeletter.agency
   getOrder -order=0
   getAuthz -order=0 -identifier=threeletter.agency
   getChall -order=0 -identifier=threeletter.agency -type=http-01
   solve -order=0 -identifier=threeletter.agency -challengeType=http-01
   poll -order=0
   finalize -order=0
   poll -order=0 -status=valid
   getCert -order=0
Low Level Commands
  • b64url - BASE64URL encoding/decoding utility.
  • challSrv - add/remove challenge responses from the built-in challenge server or the -challsrv provided on the command line.
  • csr - utility for creating a CSR for specified names or for the identifiers in a specified order with a random private key or another ACMEShell key.
  • get - HTTP GET an arbitrary URL. E.g. a terms of service URL.
  • jwsDecode - Decode a JSON JWS and its BASE64URL encoded fields.
  • post - HTTP POST an arbitrary payload to an arbitrary URL.
  • sign - create a JWS for a provided message with the active account key or another ACMEShell key.
Templating

Many of the low level commands let you template values based on ACMEShell objects. There are several templating functions and variables available:

  • account - a variable for the current account ID.
  • order <order index> - a function that returns the order with the given index.
  • authz <order> <identifier> - a function that returns the authorization from the given order for the given identifier.
  • chal <authz> <type> - a function that returns the challenge of the given type from the given authorization.
  • key <id> - a function that returns the ACMEShell private key with the given ID.
  • csr <order> <key> - a function that returns a BASE64URL encoded CSR created for the identifiers from the given order and signed with the given private key.

Here's an example that shows how templating can be used with some of the low level commands:

   echo See the active account's JWK
   viewKey {{ account }}
   echo Change the active account contact info
   post -body='{"contact":["mailto:new@example.com"]}' {{ account }}
   echo Get an order
   get {{ (order 0) }}
   echo Get some authz details
   get {{ (authz (order 0) \"example.com\") }}
   echo Get some challenge details
   get {{ (chal (authz (order 0) \"example.com\") \"tls-alpn-01\") }}
   echo POST a CSR to the first order finalize URL
   post -body='{"csr":"{{ (csr (order 0) (key "example.key")) }}"}' {{ (order 0).Finalize }}

See docs/example.script.txt for a complete non-interactive demo using templating.

Tips and tricks

  • Input lines starting with a # character are ignored by ACMEShell and can be used to comment output or scripts.

  • ACMEShell supports many "readline" shortcuts. (E.g. CTRL-A to go to the beginning of the line, CTRL-L to clear the screen).

  • ACMEShell can read non-interactive input from STDIN, or from a file using the -in argument. This is useful to run acmeshell in the delve debugger:

     dlv debug github.com/cpu/acmeshell/cmd/acmeshell -- -pebble -in docs/example.script.txt
    

TODO

  • Support RSA account keys (lol).
  • revoke high level command for revocation.
  • keyAuth low level command for making key authorizations for a specific challenge with a specific key.
  • support for exiting on a command failure (e.g. for integration tests).
  • so much cleanup...
  • some unit tests would be swell.
  • better docs.
  • polish - checking for consistency between commands (e.g. -type vs -challengeType).

Directories

Path Synopsis
Package acme provides ACME protocol constants.
Package acme provides ACME protocol constants.
client
Package client provides a low-level ACME v2 client.
Package client provides a low-level ACME v2 client.
resources
Package resources provides types for representing and interacting with ACME protocol resources.
Package resources provides types for representing and interacting with ACME protocol resources.
cmd
Package cmd provides common command line tools for the acmeshell binaries.
Package cmd provides common command line tools for the acmeshell binaries.
acmeshell command
The acmeshell command line tool provides a developer-oriented command-line shell interface for interacting with an ACME server.
The acmeshell command line tool provides a developer-oriented command-line shell interface for interacting with an ACME server.
Package net provides common HTTP utilities.
Package net provides common HTTP utilities.
Package shell provides an interactive command shell and the associated acmeshell commands.
Package shell provides an interactive command shell and the associated acmeshell commands.
commands
Package commands holds types and functions common across all ACMEShell commands.
Package commands holds types and functions common across all ACMEShell commands.
commands/post
Package post implements an ACMEShell command for POSTing requests to an ACME server.
Package post implements an ACMEShell command for POSTing requests to an ACME server.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL