You'll need to have a VM running in the same GCP project that you can SSH to, with Go and terragrunt installed, and your favourite terminal multiplexer.
This config uses the gcp/test module to deploy resources necessary to run a test TesseraCT log. TesseraCT itself will run on a VM.
At a high level, these resources consists of:
- One Spanner instance with two databases:
- one for Tessera
- one for antispam
- A GCS Bucket
- Secret Manager
First, set the required environment variables:
export GOOGLE_PROJECT={VALUE}
export GOOGLE_REGION={VALUE} # e.g: us-central1
export TESSERA_BASE_NAME={VALUE} # e.g: test-static-ct
![TIP]
TESSERA_BASE_NAME
will be used to prefix the name of various resources, and must be less than 21 characters to avoid hitting naming limits.
Then authenticate via gcloud
as a principle with sufficient ACLs for
the project:
gcloud auth application-default login --project=$GOOGLE_PROJECT
Apply the Terragrunt config to deploy resources:
terragrunt apply --terragrunt_working_dir=deployment/live/gcp/test
![NOTE] The first time you run this command, Terragrunt will ask whether you want to create a Terragrunt remote state bucket. Answer
y
.
Store the Secret Manager resource ID of signer key pair into environment variables:
export TESSERACT_SIGNER_ECDSA_P256_PUBLIC_KEY_ID=$(terragrunt output -raw ecdsa_p256_public_key_id -terragrunt-working-dir=deployment/live/gcp/test)
export TESSERACT_SIGNER_ECDSA_P256_PRIVATE_KEY_ID=$(terragrunt output -raw ecdsa_p256_private_key_id -terragrunt-working-dir=deployment/live/gcp/test)
On the VM, run the following command to bring TesseraCT up:
go run ./cmd/gcp/ \
--bucket=${GOOGLE_PROJECT}-${TESSERA_BASE_NAME}-bucket \
--spanner_db_path=projects/${GOOGLE_PROJECT}/instances/${TESSERA_BASE_NAME}/databases/${TESSERA_BASE_NAME}-db \
--spanner_antispam_db_path=projects/${GOOGLE_PROJECT}/instances/${TESSERA_BASE_NAME}/databases/${TESSERA_BASE_NAME}-antispam-db \
--roots_pem_file=./internal/testdata/fake-ca.cert \
--origin=${TESSERA_BASE_NAME} \
--signer_public_key_secret_name=${TESSERACT_SIGNER_ECDSA_P256_PUBLIC_KEY_ID} \
--signer_private_key_secret_name=${TESSERACT_SIGNER_ECDSA_P256_PRIVATE_KEY_ID} \
--otel_project_id=${GOOGLE_PROJECT}
In a different terminal you can either mint and submit certificates manually, or use the ct_hammer tool to do this.
Generate a chain manually. The password for the private key is gently
:
mkdir -p /tmp/httpschain
openssl genrsa -out /tmp/httpschain/cert.key 2048
openssl req -new -key /tmp/httpschain/cert.key -out /tmp/httpschain/cert.csr -config=internal/testdata/fake-ca.cfg
openssl x509 -req -days 3650 -in /tmp/httpschain/cert.csr -CAkey internal/testdata/fake-ca.privkey.pem -CA internal/testdata/fake-ca.cert -outform pem -out /tmp/httpschain/chain.pem -provider legacy -provider default
cat internal/testdata/fake-ca.cert >> /tmp/httpschain/chain.pem
Finally, submit the chain to TesseraCT:
go run github.com/google/certificate-transparency-go/client/ctclient@master upload --cert_chain=/tmp/httpschain/chain.pem --skip_https_verify --log_uri=http://localhost:6962/${TESSERA_BASE_NAME}
Run certificate-transparency-go' CT hammer:
go run github.com/google/certificate-transparency-go/trillian/integration/ct_hammer@master
--ct_http_servers=localhost:6962/${TESSERA_BASE_NAME} \
--max_retry=2m \
--invalid_chance=0 \
--get_sth=0 \
--get_sth_consistency=0 \
--get_proof_by_hash=0 \
--get_entries=0 \
--get_roots=0 \
--get_entry_and_proof=0 \
--max_parallel_chains=4 \
--skip_https_verify=true \
--operations=10000 \
--rate_limit=150 \
--log_config=./internal/testdata/hammer.cfg \
--testdata_dir=./trillian/testdata/
We'll run a TesseraCT instance and copy certificates from an existing RFC6962 log to it. It uses the ct_hammer tool from certificate-transparency-go.
First, save the source log URI:
export SRC_LOG_URI=https://ct.googleapis.com/logs/xenon2022
Then, get fetch the roots the source logs accepts, and edit configs accordingly. Two roots that TesseraCT cannot load with the internal/lax509 library need to be removed.
mkdir -p /tmp/hammercfg
cp ./internal/testdata/hammer.cfg /tmp/hammercfg
go run github.com/google/certificate-transparency-go/client/ctclient@master get-roots --log_uri=${SRC_LOG_URI} --text=false | \
awk \
'/-----BEGIN CERTIFICATE-----/{c=1; pem=$0; show=1; next}
c{pem=pem ORS $0}
/-----END CERTIFICATE-----/{c=0; if(show) print pem}
($0=="MIIFxDCCBKygAwIBAgIBAzANBgkqhkiG9w0BAQUFADCCAUsxGDAWBgNVBC0DDwBT"||$0=="MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB"){show=0}' \
> /tmp/hammercfg/roots.pem
sed -i 's-""-"/tmp/hammercfg/roots.pem"-g' /tmp/hammercfg/hammer.cfg
Run TesseraCT with the same roots:
go run ./cmd/gcp/ \
--bucket=${GOOGLE_PROJECT}-${TESSERA_BASE_NAME}-bucket \
--spanner_db_path=projects/${GOOGLE_PROJECT}/instances/${TESSERA_BASE_NAME}/databases/${TESSERA_BASE_NAME}-db \
--roots_pem_file=/tmp/hammercfg/roots.pem \
--origin=${TESSERA_BASE_NAME} \
--spanner_antispam_db_path=projects/${GOOGLE_PROJECT}/instances/${TESSERA_BASE_NAME}/databases/${TESSERA_BASE_NAME}-antispam-db \
--signer_public_key_secret_name=${TESSERACT_SIGNER_ECDSA_P256_PUBLIC_KEY_ID} \
--signer_private_key_secret_name=${TESSERACT_SIGNER_ECDSA_P256_PRIVATE_KEY_ID} \
--otel_project_id=${GOOGLE_PROJECT}
-v=3
Run ct_hammer
in a different terminal:
go run github.com/google/certificate-transparency-go/trillian/integration/ct_hammer@master \
--ct_http_servers=localhost:6962/${TESSERA_BASE_NAME} \
--max_retry=2m \
--invalid_chance=0 \
--get_sth=0 \
--get_sth_consistency=0 \
--get_proof_by_hash=0 \
--get_entries=0 \
--get_roots=0 \
--get_entry_and_proof=0 \
--max_parallel_chains=4 \
--skip_https_verify=true \
--operations=10000 \
--rate_limit=150 \
--log_config=/tmp/hammercfg/hammer.cfg \
--src_log_uri=${SRC_LOG_URI}