# Google Cloud ACME Setup Guide Trustico® CaaS for Google Cloud is a small job that runs once a day inside your own Google Cloud project. It issues your Trustico® SSL Certificate through the Automatic Certificate Management Environment (ACME) protocol, installs it in Google, in Certificate Manager, the classic Compute store, or both, and reissues it before it expires, every time, with no further work from you. What you use the SSL Certificate with is yours : the job puts it where Google services read it and stops there, and from there a script can do whatever you want with it : Trustico® supplies scripts for load balancers under "Optional Extras", and you can write your own for anything else. Your private keys never leave your project. This guide takes you from nothing to a running job. Every step is one screen in the Google Cloud console or one command in Cloud Shell, and every file you need is downloaded from one address : ``` https://cdn.trustico.com/caas/gcloud/ ``` | File | What it is | | ----------------------------------- | ----------------------------------------------------------------------------------------- | | `README.md` | This guide | | `job.yaml` | The job configuration file : the only configuration there is (step 4) | | `create-failed-execution-alert.sh` | Optional : an alert when a run fails (see "Optional Extras") | | `install-classic-proxy-script.sh` | Optional : the load balancer script for the classic Compute store (see "Optional Extras") | | `install-certificate-map-script.sh` | Optional : the load balancer script for Certificate Manager (see "Optional Extras") | ## Using an AI Assistant This guide is written so that an AI assistant can follow it with you, and that saves most of the reading and the typing. Give your assistant the address of this guide, `https://cdn.trustico.com/caas/gcloud/README.md`, and ask it to walk you through the steps one at a time. It can explain any screen before you open it, prepare your job configuration file with your values in place of the placeholders, and tell you what a line in a log means. The values only you know (the three subscription values, your bucket name, your service account's e-mail address, your DNS provider's details, your domain names and the name you give the SSL Certificate) are yours to supply. Keep the credentials among them in Secret Manager, as step 4 shows : the job configuration file then names each secret and never holds one, so your assistant never needs to see a credential. ## Before You Start You need these four things. Have them ready before step 1. 1. **Your Trustico® CaaS subscription**, covering every name you want on the SSL Certificate. A wildcard (`*.example.com`) and its base name (`example.com`) are two names. With the subscription you received three values : the **directory address**, the **EAB key id** and the **EAB HMAC key**. You will type them into the job configuration file. 2. **A Google Cloud project**, and an account on it with the **Owner** role. The Editor role is not enough : it can create the bucket, the service account and the job, but it cannot grant the roles that steps 3, 4 and 7 ask for ; if you only have Editor, ask whoever has Owner to make those grants. 3. **Access to your domain's DNS.** The job proves you control your names by writing a small temporary record in your DNS, through your DNS provider's API. Your provider must be one that lego, the ACME client inside the job, supports : the list, with the variables each provider needs, is at https://go-acme.github.io/lego/dns/ . That page describes the latest lego ; this job runs lego v5.5.2, so a provider is available only if the page shows it as present at v5.5.2 or earlier. If your DNS is on Google Cloud DNS in the same project as the job, you need no credential at all ; if the zone is in another project, steps 3 and 4 say what to do. 4. **About thirty minutes.** ## Step 1 : Enable the APIs In the console : **APIs & Services, Enable APIs and services**. Search for and enable : - **Certificate Manager API**, and the **Compute Engine API** if you will use the classic Compute store, alone or as well (it is usually enabled already). - **Cloud Run Admin API** and **Cloud Scheduler API**. - **Cloud DNS API**, only if your DNS is on Google Cloud DNS. - **Secret Manager API**, only if you will keep a credential in Secret Manager (step 4). ## Step 2 : Create the Bucket A Cloud Run job has no disk of its own : every run starts empty and keeps nothing when it ends. The job therefore needs one place that lasts between runs, and that place is a Cloud Storage bucket, a private folder in your project. In it the job keeps the account it opens with your subscription, every SSL Certificate it has issued and the private key of each one, in the layout of lego, the ACME client inside the job. On every run it reads what is there, decides whether anything is due, and writes back whatever it issued. Nothing in the bucket ever leaves your project. In the console : **Cloud Storage, Buckets, Create**. - **Name** : any name of your choosing. Write it down ; you will type it into the job configuration file in step 4. - **Location** : any region. The region you will give the job in step 5 is as good as any. - **Data protection** : tick **Object versioning**. Every time the job replaces a file, the version it replaced is then kept as an older version, and that is your rollback : if a reissue ever has to be undone, the previous key and SSL Certificate are still there. The form shows two numbers beside the tick and offers 1 for each ; those defaults exist to save storage, and with them the previous version would be deleted a day after the reissue. Set **Max. number of versions per object** to **5** (the count includes the current version, so this keeps the four before it) and **Expire noncurrent versions after** to **365** days (anything older than a year has expired and is of no use). Leave the soft delete policy as the form offers it. Everything else can stay as it is. Never put anything into this bucket yourself and never delete anything from it : the job expects to find exactly what it wrote, and a file placed or removed by hand can make it issue again when nothing is due, or fail to find its account. ## Step 3 : Create the Service Account Everything that runs in Google Cloud runs as an identity, and a program gets an identity of its own, called a service account. Giving the job a service account of its own means it has only the permissions this guide grants it, each for one thing the job does, and no access to anything else in your project. The permissions are given as roles. In the console : **IAM & Admin, Service Accounts, Create service account**. - **Name** : any name, for example `trustico-caas`. Google shows an e-mail address for it, ending in `.iam.gserviceaccount.com`. Write it down ; you will type it into the job configuration file in step 4. - On the same screen, under **Grant this service account access to project**, add the roles the job needs, then **Done** : - **Certificate Manager Editor** : lets the job create your SSL Certificate in Certificate Manager and update it in place on every reissue. Needed for the Certificate Manager store. - **Compute Load Balancer Admin** : lets the job add a new SSL Certificate resource to the classic Compute store each time one is due. Needed for the classic store, instead of the role above or as well as it if you use both stores. - **DNS Administrator** : lets the job write the temporary validation record in a Google Cloud DNS zone. Needed only when your DNS is on Google Cloud DNS ; with any other provider the job uses that provider's own credential (step 4) and needs no Google role for it. If your zone lives in a different project, grant this role there instead : switch to that project, **IAM & Admin, IAM, Grant access**, the service account's e-mail as the principal. Then give it the bucket. None of the roles above opens the bucket, because a bucket has permissions of its own. **Cloud Storage, Buckets**, open the bucket of step 2, **Permissions, Grant access** : the service account's e-mail as the principal, the role **Storage Object User**, which lets the job read and write the files in that one bucket and nothing else. ## Step 4 : Prepare the Job Configuration File A Cloud Run job is defined by a set of settings : the image to run, the bucket to mount, the service account to run as, and the variables the program reads. The job configuration file holds all of them in one text file, so that you fill in the form once, by hand, and in step 5 hand the whole form to Google in one go instead of typing it field by field in the console. Everything the job does is decided by this file ; there is no other configuration anywhere, and every later change to the job is an edit to this file followed by step 5 again. Keep it with your own files : Google keeps the job you create from it, not the file, and your copy is the one you edit from now on ("Afterwards" says how to read it back from Google if you ever lose it). Download `https://cdn.trustico.com/caas/gcloud/job.yaml` and open it in any text editor (Notepad, TextEdit, VS Code). Every line that needs a value of yours has a comment right above it saying what to put there. The lines fall into three kinds, and two parts of the file need a word more. **Values that are yours.** Every value that begins with `YOUR` is a placeholder for something only you know : your bucket name (step 2), your directory address, EAB key id and EAB HMAC key (from your subscription), the name you give the SSL Certificate, your domain names, your DNS provider's code and its variables (from lego's page), and your service account's e-mail address (step 3). Replace each with your own value. The job refuses to start while the directory address, the name of the SSL Certificate, the domain names or the provider code still holds its placeholder, and tells you which. It cannot check your EAB key id and HMAC key or your provider's variables, because to the job a wrong value looks like any other value : copy those exactly, since a mistake there shows up later as an error from lego (the last two rows of the table under "If Something Goes Wrong"). **Choices.** Lines marked **your choice** are decisions rather than facts : the name the SSL Certificate will have in Google and the names on it (yours), the key type (`ec256` is fine for almost everyone), the store or stores (**Certificate Manager**, the recommended one, where every reissue updates the same SSL Certificate and whatever uses it never needs touching again ; the classic **Compute** store, where each reissue is a new numbered resource ; or both, written `certificate-manager,compute`, so the one SSL Certificate is kept in each), and the location and the scope (keep `global` and `DEFAULT` unless the comment tells you otherwise for what will use the SSL Certificate). If Certificate Manager is not among your stores, delete the two entries `CERT_1_CM_LOCATION` and `CERT_1_CM_SCOPE` entirely, from their `- name:` lines to their `value:` lines : they belong to Certificate Manager and the job refuses them without it. **Lines that stay as they are.** Every other line is right already. Keep the double quotes around every value under `env`, whatever it contains : Google reads an unquoted number, or a word such as `yes` or `no`, as a number or a switch rather than as the text the job expects. The `image`, `name` and `serviceAccountName` lines carry no quotes and need none. **The DNS provider block.** The job proves you control your names by writing a temporary record in your DNS, so it needs a way into your DNS provider's API. Put your provider's code in `DNS_PROVIDER`, then one entry per variable your provider needs, with the names and values lego's page gives for it (the API key, token or account details that provider uses). If your DNS is on Google Cloud DNS in this same project, the code is `gcloud`, the DNS Administrator role of step 3 is the credential, and you delete the `YOUR_PROVIDER_VARIABLE` entry entirely (from its `- name:` line to its `value:` line) ; if the zone is in another project, rename that entry to `GCE_PROJECT` and give it that project's ID as its value. **Keeping credentials out of the file.** The EAB HMAC key and your DNS provider's credential are secrets, and a job configuration file with them typed in has to be guarded like one. Secret Manager is Google's store for secrets, and a job can read a value from it at the moment it starts, so the file need only name the secret. For each credential : **Security, Secret Manager, Create secret**, any name, the credential as the value ; then on that secret, **Permissions, Grant access** : your service account, role **Secret Manager Secret Accessor**, which lets the job read that one secret. In the job configuration file, replace that variable's `value:` line with these four lines, indented the same way, with your secret's name on the `name:` line : ```yaml valueFrom: secretKeyRef: name: YOUR-SECRET-NAME key: latest ``` The file then holds no secret at all and can be kept, copied or shown to an assistant freely. ## Step 5 : Create the Job The surest way is one command in Cloud Shell, the terminal built into the console. 1. Open **Cloud Shell** (the terminal icon at the top right of the console). 2. Upload your edited `job.yaml` : the **three-dot menu** of the Cloud Shell window, **Upload**, choose the file. 3. Run, with the region you want the job to live in (any region ; write it down for step 7) : ``` gcloud run jobs replace job.yaml --region=us-central1 ``` Cloud Shell may ask to enable an API or to confirm the project : answer yes. When it finishes, the job appears under **Cloud Run, Jobs**. Whenever this guide says **apply**, it means : upload your edited `job.yaml` to Cloud Shell again and run this command again. If you prefer the console form : **Cloud Run, Jobs, Create job**, and enter the same values from your job configuration file field by field : the image address, the service account, under **Volumes** a Cloud Storage volume of your bucket and, on the container, that volume mounted at `/state`, under **Variables** every variable and value from the file, and under the task settings a **Task timeout** of 60 minutes and **Number of retries per failed task** of 0, as the file has them (the form's own defaults are 10 minutes and 3 retries, and 3 retries would hammer the Certificate Authority after a failure). ## Step 6 : Run It Once Open the job under **Cloud Run, Jobs**, and press **Execute**. The first run takes one to two minutes : it registers your account, proves control of your names in your DNS, obtains the SSL Certificate, saves it in your bucket, and creates it in each store you chose : in Certificate Manager under the name you gave in `CERT_1_NAME`, in the classic store as the resource `CERT_1_NAME-01`. Open the execution under the job's **History** to read its log. A good run ends with : ``` TRUSTICO® CAAS FOR GOOGLE CLOUD COMPLETE : EVERY SSL CERTIFICATE CURRENT AND INSTALLED ``` If it ends with a line containing `FAILED` or `REFUSING TO RUN` instead, see "If Something Goes Wrong" below, fix the cause, and press **Execute** again. Nothing is harmed by running it again. ## Step 7 : Schedule It Daily The job runs only when something starts it. A Cloud Scheduler schedule starts it once a day. There are two ways to create the schedule, and both work : from the job's own **Triggers** tab, which fills most of the form in for you and lists the schedule under the job afterwards, or directly in Cloud Scheduler, where you type every field yourself. The first is the easier. One schedule per job. If you run more than one job, give each its own hour, for example 04:00 and 05:00, so that two jobs never work at the same moment. ### From the Job's Triggers Tab 1. **Cloud Run, Jobs**, open your job, open the **Triggers** tab, press **Add Scheduler Trigger**. If the console asks to enable the Cloud Scheduler API, enable it. 2. **Name** : keep the name the form offers, `YOUR-JOB-NAME-scheduler-trigger`. **Region** : keep the one offered ; it does not need to match the job's. **Frequency** : `0 4 * * *` (every day at 04:00). **Timezone** : type `UTC` in the search box and choose **Coordinated Universal Time (UTC)**. Press **Continue**. 3. **Configure the execution** : the target, the address, the method and the token type are already filled in ; leave them. The one field to change is **Service account** : the form offers your project's default compute account. Open the list and choose the job's own service account instead, the one whose e-mail address you wrote down in step 3. Press **Create**. The schedule now appears under the job's Triggers tab, and in Cloud Scheduler. ### Directly in Cloud Scheduler In the console : **Cloud Scheduler, Create job**. The form has three parts ; fill them in this order, and leave every field this step does not name exactly as the form offers it. **Define the schedule** - **Name** : `YOUR-JOB-NAME-scheduler-trigger`, the same shape the Triggers tab would give it. - **Region** : any. - **Description** : leave empty. - **Frequency** : `0 4 * * *` (every day at 04:00). - **Timezone** : type `UTC` in the search box and choose **Coordinated Universal Time (UTC)**. Press **Continue**. **Configure the execution** - **Target type** : HTTP. - **URL** : the address below, with your three values in place of the placeholders. ``` https://run.googleapis.com/v2/projects/YOUR-PROJECT-ID/locations/YOUR-REGION/jobs/YOUR-JOB-NAME:run ``` `YOUR-PROJECT-ID` is your project's ID, shown on the console's home page. `YOUR-REGION` is the region you created the job in, in step 5. `YOUR-JOB-NAME` is the `name` at the top of your job file (`trustico-caas` unless you changed it). The `:run` at the end stays. - **HTTP method** : POST. - **HTTP headers** : leave empty. - **Body** : leave empty. - **Auth header** : **Add OAuth token**. Not OIDC : the job is started through Google's own API, which takes an OAuth token. - **Service account** : the job's service account, the one whose e-mail address you wrote down in step 3. Pick it from the list by that e-mail address. Not your own account. - **Scope** : leave as the form offers it. Press **Continue**. **Configure optional settings** : leave everything as it is. Press **Create**. A schedule made this way starts the job exactly as the other does. It is listed in Cloud Scheduler but not under the job's Triggers tab, because the console lists there only the schedules it created itself. ### Either Way : Let the Account Start the Job, Then Prove It **Give the service account the right to start the job.** The schedule runs as the job's service account, and that account needs one more role, on the job itself. Neither form grants it. **Cloud Run, Jobs**, tick the checkbox at the left of your job ; in the panel that opens on the right, open **Permissions**, press **Add principal**, paste the service account's e-mail address, choose the role **Cloud Run Invoker**, **Save**. Without this the schedule fires every day and the job never starts. **Prove it now, instead of waiting until 04:00.** In **Cloud Scheduler**, the three-dot menu at the end of your schedule's row has **Force run**. Press it, then open **Cloud Run, Jobs**, the job, **History** : a new execution appears within a few seconds and, a few seconds later, ends with the COMPLETE line of step 6 (it has nothing to reissue, so it only checks and verifies). If the schedule's row shows **Failed** and no execution appears under the job, the cause is the Cloud Run Invoker grant above or the service account chosen in the form. That is the whole setup. Every day at the hour you chose the job runs, checks whether the SSL Certificate is due (about thirty days before it expires), reissues it when it is, and installs it in place. ## Afterwards Every later change to the job is the same two moves : edit the copy of the job configuration file you kept, and apply it (upload the edited file to Cloud Shell again and run the command of step 5). Then press **Execute**, or let the next daily run pick the change up. - **Checking on it** : **Cloud Run, Jobs**, the job, **History** shows every run and whether it succeeded. A day with nothing to do completes in a few seconds. - **Your job configuration file** : the copy you kept is the one you edit ; Google holds the job made from it, not the file. If you ever lose your copy, this command in Cloud Shell, with the region of step 5 and, if you changed it, the name at the top of your job file, writes it back from Google, with every secret still a reference and never a value : ``` gcloud run jobs describe trustico-caas --region=us-central1 --format export > job.yaml ``` - **Changing the names** : edit `CERT_1_DOMAINS`. The list is the whole list, so a name you add goes on and a name you take out comes off. The SSL Certificate is reissued at once with exactly these names, into the same SSL Certificate in Certificate Manager, and as a new numbered resource in the classic store. If a Certificate Map serves the SSL Certificate, the new name needs an entry : add it by hand, or run the Certificate Manager installer again with the new hostnames (see "Optional Extras") ; the classic store script needs nothing. - **A second SSL Certificate** : copy the `CERT_1_` block in the job configuration file as `CERT_2_` with its own name and names. - **A second subscription** : copy the `ACCOUNT_1_` block as `ACCOUNT_2_` with its own values, and give the SSL Certificates that belong to it an entry `CERT_N_ACCOUNT` with value `"2"`. - **Removing an SSL Certificate or a subscription** : delete its block (for a subscription, together with the `CERT_` blocks that belong to it), and renumber the blocks after it so that they still count from 1 without a gap. A `CERT_N_ACCOUNT` entry names a subscription by its number, so when a subscription's number changes, change every entry that named it to the new number. The job stops managing what you removed and deletes nothing : the SSL Certificate stays in Google, and its files stay in the bucket, until you remove them yourself. - **What cannot change** : the name of an SSL Certificate, and its Certificate Manager location and scope. A different name is a new SSL Certificate : add it as a new block and remove the old one as above. - **A new version of the job** : Trustico® publishes approved updates under the same image name, and your job takes each one on its next run. There is nothing to apply and nothing to edit ; the first line of every run names the version and the build that ran. - **A new version of an Optional Extra** : download its installer again and run it again with the same answers. "Optional Extras" says what each one does when run again. ## If Something Goes Wrong A failed run is marked **Failed** under **History**. Open it and read its last lines. A run that refused to start ends with a line ending `REFUSING TO RUN` (the first two rows below). Otherwise find the line `SSL CERTIFICATE NOT CURRENT OR NOT INSTALLED` ; the lines above it say why. The ones you may meet : | In the log | Cause | Fix | | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | `REQUIRED CONFIG MISSING OR INVALID` | One of the placeholders the job checks left in the job configuration file, or a value in the wrong form | Expand the line (click it) to see every problem listed ; fix them all, apply, execute again | | `STATE PATH IS NOT A WRITABLE DIRECTORY` | The bucket is not mounted, or the service account cannot write to it | Check the bucket name in the job configuration file and the Storage Object User role of step 3 | | `INSTALL FAILED` with Google's message | A missing role, or an API not enabled | Steps 1 and 3 ; Google's message names what is missing | | `Key Identifier was not recognized` (from lego) | The EAB key id or HMAC key is wrong, or still a placeholder | Check the three subscription values against what Trustico® supplied | | A DNS error from lego, such as `domain not found` | The DNS credential has no rights on that zone, the wrong provider, or a variable still a placeholder | Check the provider's code and variables against lego's page for your provider | A failed run is not retried the same day ; the next scheduled run starts from scratch, and you can always press **Execute** yourself. ## Optional Extras Optional Extras are small scripts from Trustico® that do useful things with the SSL Certificate once the job has installed it. The job runs the same without them. Each one is a single file. Open it at the address below, read the instructions at the top, download it, and run it in Cloud Shell. It asks you a few questions, shows you the choices it finds in your project, and changes nothing until you type yes. Each installer can be run again at any time : when your answers change, or when Trustico® publishes a new version of a script, download the installer again and run it again. The two load balancer installers apply your answers again and leave what already matches as it is ; the alert script reports that the alert exists, so to change it, delete the alert under **Monitoring, Alerting, Policies** and run the script again. None of them deletes anything. You can also write your own scripts and do anything you like with the SSL Certificate in your Google Cloud project, on a load balancer, a virtual machine, a Kubernetes cluster or anything else. These are the scripts Trustico® supplies today, and more will follow. ### An Alert When a Run Fails The job does not send a message when a run fails. This script sets up an alert that e-mails you, or notifies you another way you choose, whenever that happens. The file : https://cdn.trustico.com/caas/gcloud/create-failed-execution-alert.sh ### The Load Balancer Script for the Classic Compute Store In the classic Compute store every reissue is a new SSL Certificate resource, and a load balancer keeps using the old one until it is told otherwise. This script tells it. Every day, after the job, it puts the newest SSL Certificate on your load balancer, and on a day with nothing new it does nothing. The file : https://cdn.trustico.com/caas/gcloud/install-classic-proxy-script.sh ### The Load Balancer Script for Certificate Manager With Certificate Manager a load balancer finds its SSL Certificate through a Certificate Map, which says which SSL Certificate to use for which hostname. The job updates that SSL Certificate in place, so the map only has to point at it once : one entry per hostname, each naming the SSL Certificate you gave `CERT_1_NAME`. If you are comfortable in the console, you can make those entries yourself (**Security, Certificate Manager, Certificate Maps**, your map, **Edit**, **Add map entry**) and you do not need this script. This script makes the same entries for you, for each of your hostnames, and then checks every day that they still point at the SSL Certificate the job keeps up to date. When you add a name to the SSL Certificate, add its entry the same way you made the others : by hand, or by running the installer again with the new hostname. An entry for a hostname you no longer use stays in the map until you delete it. The file : https://cdn.trustico.com/caas/gcloud/install-certificate-map-script.sh ## Reference : Every Setting in the Job Configuration File Blocks are numbered from 1 and must be consecutive. Every value stays in double quotes. | Setting | Value | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ACCOUNT_N_DIRECTORY_URL` | The directory address supplied with your subscription. One `ACCOUNT` block per subscription | | `ACCOUNT_N_NAME` | A name of your choosing for the subscription : lowercase letters, digits and hyphens, a letter first, at most 50 characters ; different in each block | | `ACCOUNT_N_EAB_KID` | The EAB key id supplied with your subscription | | `ACCOUNT_N_EAB_HMAC_KEY` | The EAB HMAC key supplied with your subscription (typed, or a Secret Manager reference as step 4 shows) | | `CERT_N_NAME` | The name of the SSL Certificate in Google : lowercase letters, digits and hyphens, a letter first, at most 50 characters. Keep it for good. With the classic store the job adds `-01`, `-02`, ... to it, so with that store the name must not itself end in a hyphen and digits (`tc-example-com-2026` is refused ; `tc-example-com` is fine) | | `CERT_N_DOMAINS` | The names on the SSL Certificate, comma-separated. A wildcard and its base name are two names. Changing the list reissues with exactly these names | | `CERT_N_ACCOUNT` | Only with more than one subscription : the number of the `ACCOUNT` block this SSL Certificate belongs to. Leave out for 1 | | `CERT_N_KEY_TYPE` | `ec256`, `ec384`, `rsa2048`, `rsa3072` or `rsa4096`. The classic store takes `ec256` and `rsa2048` only | | `CERT_N_TARGET` | `certificate-manager` (recommended), `compute` (the classic store), or both as `certificate-manager,compute` : the one SSL Certificate is installed in each store named. Without `certificate-manager`, delete the two `CM` entries below | | `CERT_N_CM_LOCATION` | `global`, unless the Google service that will use the SSL Certificate requires it in a region ; that service's documentation says. Cannot be changed later | | `CERT_N_CM_SCOPE` | `DEFAULT`, unless the Google service that will use the SSL Certificate requires `ALL_REGIONS` or `EDGE_CACHE` ; that service's documentation says. Cannot be changed later | | `REISSUE_DAYS` | Optional : how many days before expiry to reissue. Leave out for the default, a third of the lifetime | | `DNS_PROVIDER` | Your DNS provider's code from lego's page, with that provider's own variables as further entries. One provider per job | | `DNS_RESOLVERS` | Optional : public resolvers the job checks your record against, comma-separated `host:port` | | `STATE_PATH` | Optional : where the bucket is mounted. Leave out for `/state`, which the job configuration file uses | | `LOG_LEVEL` | Optional : `info` unless you want more detail (`debug`) | | `USER_AGENT` | Optional : leave out |