# InVEST Codesigning Service

This directory contains all of the functional code and configuration (minus a
few secrets) that are needed to deploy our code-signing service.  There are
three key components to this service:

1. A cloud function (`gcp-cloudfunc/') that handles a google cloud
   storage-backed cloud function that operates as a high-latency queue.
2. A script (`enqueue-binary.py`) that will enqueue a binary that already
   exists on one of our GCS buckets.
3. A `systemd` service that runs on a debian:bookworm machine and periodically
   polls the cloud function to dequeue the next item to sign.

## Deploying the Cloud Function

The necessary `gcloud` deployment configuration can be executed with

```bash
$ make deploy-cloudfunction
```

### Secrets

The current deployment process requires you to manually create an environment
variable, ``ACCESS_TOKEN``, that contains the secret token shared by the cloud
function, systemd service and enqueue script.

## Deploying the Systemd Service

To deploy the systemd service, you will need to be on a computer that has ssh
access to `ncp-inkwell`, which is a computer that has a yubikey installed in
it.  This computer is assumed to run debian:bookworm at this time.  To deploy
(non-secret) changes to ncp-inkwell, run this in an environment where
`ansible-playbook` is available (`pip install ansible` to install):

```bash
$ make deploy-worker
```

### Useful debugging commands

* `sudo systemctl status natcap-codesign.service` will show the current status
  of the service. Instead of `status`, you can also say `start`, `stop`, or a
  few other verbs described in the systemctl docs.
* `sudo journalctl -u natcap-codesign.service -n 300` will show the 300 most
  recent log messages generated by the service.
* `sudo journalctl -u natcap-codesign.service -n 300 --follow` will show the
  300 most recent log messages generated by the service and also show live
  additions to the logfile as they are logged.

### Secrets

The systemd service requires several secrets to be available in the codesigning
workspace, which is located at `/opt/natcap-codesign':

* `/opt/natcap-codesign/pass.txt` is a plain text file containing only the PIN
  for the yubikey
* `/opt/natcap-codesign/access_token.txt` is a plain text file containing the
  access token shared with the cloud function, systemd service and enqueue script.
* `/opt/natcap-codesign/slack_token.txt` is a plain text file containing the
  slack token used to post messages to our slack workspace.
* `/opt/natcap-codesign/natcap-servers-1732552f0202.json` is a GCP service
  account key used to authenticate to google cloud storage.  This file must be
  available in the `gcp-cloudfunc/` directory at the time of deployment.
* `/opt/natcap-codesign/mac-certificate.p12` is a p12 certificate for mac
  codesigning.  This is a Developer ID Application certificate.
* `/opt/natcap-codesign/mac-certificate-pass.txt` is a text file containing the
  password for the mac certificate.


## Future Work

### Authenticate to the function with Identity Federation

The cloud function has access controlled by a secret token, which is not ideal.
Instead, we should be using github/GCP identity federation to control access.

### Trigger the function with GCS Events

GCP Cloud Functions have the ability to subscribe to bucket events, which
should allow us to subscribe very specifically to just those `finalize` events
that apply to the Windows workbench binaries.  Doing so will require reworking this cloud function into 2 cloud functions:

1. An endpoint for ncp-inkwell to poll for the next binary to sign
2. A cloud function that subscribes to GCS bucket events and enqueues the binary to sign.

Relevant docs include:
* https://cloud.google.com/functions/docs/writing/write-event-driven-functions#cloudevent-example-python

