There are two simple ways to set up Fulcio.
The first is to use docker-compose up
. This sets up both Fulcio and the Trillian instance
used for the certificate transparency (CT) log. See below for details on customizing the signing
backend, as the default uses an ephemeral CA that is not persisted.
Simply run:
docker-compose up
If you need to change the docker port on which the metrics port is bound, use
the FULCIO_METRICS_PORT
variable:
export FULCIO_METRICS_PORT=2113
docker-compose up
The other way is running the Fulcio binary:
go run main.go serve --port 5555 --ca ephemeralca --ct-log-url=""
This serves the API without a CT log, which is not recommended for production. See sigstore-the-local-way to learn more about setting up Trillian.
Fulcio supports various modes to generate its code-signing certificates. These modes support different signing backends that are responsible for both generating and signing a certificate.
Note that when using docker-compose
, you may need to mount files under volumes
.
The KMS signing backend uses KMS to generate a certificate signature. This requires setting up a KMS key with a cloud provider, such as AWS, GCP, Azure or Hashicorp Vault. You will also need to certify the public key of the signer, providing a certificate chain. The CA can either run as an intermediate CA chaining up to an offline root CA, or as a root CA, though the KMS signing backend is primarily meant to be used as an intermediate CA.
Configuration:
--ca=kmsca
--kms-resource=gcpkms://<resource>
, also supportingawskms://
,azurekms://
orhashivault://
--kms-cert-chain-path=/...
, a PEM-encoded certificate chain
Be sure to run gcloud auth application-default login
before docker-compose up
so that
your credentials are mounted on the container.
The Tink signing backend uses an on-disk signer loaded from an encrypted Tink keyset and certificate chain, where the first certificate in the chain certifies the public key from the Tink keyset. The Tink keyset must be encrypted with a GCP KMS key, and stored in a JSON format. The CA can either run as an intermediate CA chaining up to an offline root CA, or as a root CA.
Tink keysets use strong security defaults and are the most secure way to store an encryption key locally.
The supported Tink keysets are:
- ECDSA P-256, SHA256 hash
- ECDSA P-384, SHA512 hash
- ECDSA P-521, SHA512 hash
- ED25519
Configuration:
--ca=tinkca
--tink-kms-resource=gcp-kms://<resource>
, also supportingaws-kms://
--tink-keyset-path=/...
, a JSON-encoded encrypted Tink keyset--tink-cert-chain-path=/...
, a PEM-encoded certificate chain
Be sure to run gcloud auth application-default login
before docker-compose up
so that
your credentials are mounted on the container.
The GCP CA Service signing backend delegates creation and signing of the certificates to a CA managed in GCP. You will need to create a DevOps-tier CA pool and one CA in the CA pool. This can either be an intermediate or root CA.
We currently do not support the following CA Service configurations. Please file an issue if you need support.
- Enterprise-tier CA pools (The certificate ID is not sent in the request)
- CA pools with multiple CAs (Multiple places in the code expect only one certificate chain)
Configuration:
--ca=googleca
--gcp_private_ca_parent=projects/<project>/locations/<location>/caPools/<CA-pool>
Be sure to run gcloud auth application-default login
before docker-compose up
so that
your credentials are mounted on the container.
The on-disk file-based signing backend loads an encrypted key and certificate chain, and also monitors for changes to either, reloading the key and chain without requiring a server reboot. This signer supports a CA as either a root or intermediate.
See generate.sh for examples of how to generate an encrypted private key using OpenSSL.
Configuration:
--ca=fileca
--fileca-cert=/...
, a PEM-encoded certificate chain--fileca-key
, a PEM-encoded encrypted signing key (RSA, ECDSA, and ED25519 are supported)--fileca-key-passwd
, the password to decrypt the signing key
The PKCS11 signing backend supports using an HSM to sign certificates.
Configuration:
--ca=pkcs11ca
--pkcs11-config-path=/...
, a path to a PKCS11 configuration. Seeconfig/crypto11.conf
--hsm-caroot-id=...
- Optional:
--aws-hsm-root-ca-path=...
, a path to an AWS HSM resource
See HSM Support for more information.
Ephemeral CAs create the key material in memory and destroy the key material on server turndown. Do not use ephemeral CAs for production.
Configuration:
--ca=ephemeralca
To view the root certificate, you can access it at
http://localhost:5555/api/v1/rootCert
:
curl http://localhost:5555/api/v1/rootCert
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
All signing backends can be configured to write issued certificates to a transparency log. Signed certificate timestamps (SCTs), proof of inclusion in the log, are returned in a custom HTTP header or gRPC field.
Only the KMS and File-based signing backends support embedded SCTs currently. Embedded SCTs are recommended, since a client can easily verify proof of inclusion when using the certificate for artifact verification, without needing to store the detached SCT alongside the certificate.
See CT Log for more information.
Certain signing backends, such as the KMS and file-based backends, require providing your own CA certificate chain. An example PEM-encoded certificate chain:
-----BEGIN CERTIFICATE-----
MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw
KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y
MjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl
LmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C
AQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7
7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS
0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB
BQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp
KFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI
zj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR
nZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP
mygUY7Ii2zbdCdliiow=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw
KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y
MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl
LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7
XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex
X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j
YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY
wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ
KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM
WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9
TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
-----END CERTIFICATE-----
Save the chain to chain.crt
and parse with
openssl crl2pkcs7 -nocrl -certfile chain.crt | openssl pkcs7 -print_certs -text -noout
.
For the root certificate:
- Subject with a common name and organization
- Key usages: Certificate Sign, CRL Sign
- CA basic constraints: CA:TRUE
- You can optionally limit the root with a path length to prevent additional CA certificates from being issued beneath that root.
- Subject public key: We recommend using ECDSA-P384 (secp384r1) or higher, or RSA-4096.
For the intermediate certificate:
- Subject with a common name and organization
- Key usages: Certificate Sign, CRL Sign
- Extended key usage: Code Signing
- Lifetime does not exceed the parent certificate
- CA basic constraints: CA:TRUE, pathlen:0
- You can choose to add a different path length constraint, but we recommend limiting the intermediate CA to only issue leaf certificates.
- Subject public key: We recommend using ECDSA-P384 (secp384r1) or higher, or RSA-4096. We don't recommend mixing signing algorithms within the chain.
To call Fulcio, you can either use curl
or the gRPC client. It's easiest to use
Cosign to call the local instance of Fulcio. You can configure Cosign to call
the local instance with --fulcio-url
, for example:
cosign sign --yes --fulcio-url http://localhost:5555 container
You will also need to configure Cosign with the local instance's root certificate and CT log public key. You can do so by setting up a local TUF repository, following this guide
Alternatively, for non-production testing only, you can use environment variables to configure the root certificate and public key.
Set SIGSTORE_ROOT_FILE
with the path to a PEM-encoded root certificate.
To get the root certificate, call curl -o fulcio.crt.pem http://localhost:5555/api/v1/rootCert
.
Set SIGSTORE_CT_LOG_PUBLIC_KEY_FILE
with the path to a PEM or DER-encoded CT log public key.
If using docker-compose
, the public key is available at config/ctfe/pubkey.pem
.