Skip to content

Commit

Permalink
Introduce EJBCA UpstreamAuthority plugin for SPIRE Server (#5378)
Browse files Browse the repository at this point in the history
* feat(ejbca): Initial EJBCA UpstreamAuthority plugin

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

* chore(test): Create EJBCA UpstreamAuthority integraiton test and
refactor EJBCA config to only support certs from file

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

* Resolve bug in EJBCA integration test and resolve linting issue in EJBCA docs

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

* chore(oauth): Remove OAuth from EJBCA UpstreamAuthority plugin

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

* chore(integration): Resolve bug in EJBCA integration test and refactor to use non-OAuth server config

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

* chore(docs): Remove link fragment from EJBCA docs

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

* chore(codereview): Resolve comments from code review

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

* chore(test): Refactor EJBCA integration test to use client_cert_key_path

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

* fix(ejbca): Replace ToPluginProtos with ToPluginFromCertificates

Signed-off-by: Hayden Roszell <hroszell@gmail.com>

---------

Signed-off-by: Hayden Roszell <hroszell@gmail.com>
Co-authored-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
  • Loading branch information
m8rmclaren and amartinezfayo authored Sep 5, 2024
1 parent 904f9a9 commit 7118533
Show file tree
Hide file tree
Showing 35 changed files with 7,808 additions and 0 deletions.
33 changes: 33 additions & 0 deletions conf/server/server_full.conf
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,39 @@ plugins {
# }
# }

# UpstreamAuthority "ejbca": Uses a connected EJBCA to sign SPIRE server
# intermediate certificates
UpstreamAuthority "ejbca" {
plugin_data {
# The hostname of the connected EJBCA server.
hostname = "ejbca.example.com"
# (optional) The path to the CA certificate file used to validate the
# EJBCA server's certificate. Certificates must be in PEM format.
ca_cert_path = "/path/to/ca_cert.pem"
# The path to the client certificate (public key only) used
# to authenticate to EJBCA. Must be in PEM format.
client_cert_path = "/path/to/client_cert.pem"
# The path to the client key matching `client_cert` used to
# authenticate to EJBCA. Must be in PEM format.
client_cert_key_path = "/path/to/client_key.pem"
# The name of a CA in the connected EJBCA instance that will
# issue the intermediate signing certificates.
ca_name = "Fake-Sub-CA"
# The name of an end entity profile in the connected EJBCA
# instance that is configured to issue SPIFFE certificates.
end_entity_profile_name = "fakeSpireIntermediateCAEEP"
# The name of a certificate profile in the connected EJBCA instance
# that is configured to issue intermediate CA certificates.
certificate_profile_name = "fakeSubCACP"
# (optional) The name of the end entity, or configuration for how
# the EJBCA UpstreamAuthority should determine the end entity name.
end_entity_name = ""
# (optional) An account binding ID in EJBCA to associate with issued certificates.
account_binding_id = "abc123"
}
}


# BundlePublisher "aws_s3": A bundle publisher that puts the current trust
# bundle of the server in a designated Amazon S3 bucket, keeping it updated.
# BundlePublisher "aws_s3" {
Expand Down
82 changes: 82 additions & 0 deletions doc/plugin_server_upstreamauthority_ejbca.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Server plugin: UpstreamAuthority "ejbca"

The `ejbca` UpstreamAuthority plugin uses a connected [EJBCA](https://www.ejbca.org/) to issue intermediate signing certificates for the SPIRE server. The plugin authenticates to EJBCA using mTLS (client certificate).

> The EJBCA UpstreamAuthority plugin uses only the `/ejbca-rest-api/v1/certificate/pkcs10enroll` REST API endpoint, and is compatible with both [EJBCA Community](https://www.ejbca.org/) and [EJBCA Enterprise](https://www.keyfactor.com/products/ejbca-enterprise/).
## Requirements

* EJBCA [Community](https://www.ejbca.org/) or EJBCA [Enterprise](https://www.keyfactor.com/products/ejbca-enterprise/)
* The "REST Certificate Management" protocol must be enabled under System Configuration > Protocol Configuration.

> It's important that the EJBCA Certificate Profile and End Entity Profile are properly configured before using this plugin. The plugin does not attempt to configure these profiles. Please refer to the [EJBCA Sub CA End Entity Profile & Certificate Profile Configuration](#ejbca-sub-ca-end-entity-profile--certificate-profile-configuration) section for more information.
## Configuration

The EJBCA UpstreamAuthority Plugin accepts the following configuration options.

| Configuration | Description | Default from Environment Variables |
|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|
| `hostname` | The hostname of the connected EJBCA server. | |
| `ca_cert_path` | (optional) The path to the CA certificate file used to validate the EJBCA server's certificate. Certificates must be in PEM format. | `EJBCA_CA_CERT_PATH` |
| `client_cert_path` | The path to the client certificate (public key only) used to authenticate to EJBCA. Must be in PEM format. | `EJBCA_CLIENT_CERT_PATH` |
| `client_cert_key_path` | The path to the client key matching `client_cert` used to authenticate to EJBCA. Must be in PEM format. | `EJBCA_CLIENT_CERT_KEY_PATH` |
| `ca_name` | The name of a CA in the connected EJBCA instance that will issue the intermediate signing certificates. | |
| `end_entity_profile_name` | The name of an end entity profile in the connected EJBCA instance that is configured to issue SPIFFE certificates. | |
| `certificate_profile_name` | The name of a certificate profile in the connected EJBCA instance that is configured to issue intermediate CA certificates. | |
| `end_entity_name` | (optional) The name of the end entity, or configuration for how the EJBCA UpstreamAuthority should determine the end entity name. See [End Entity Name Customization](#ejbca-end-entity-name-customization-leaf-certificates) for more info. | |
| `account_binding_id` | (optional) An account binding ID in EJBCA to associate with issued certificates. | |

> Configuration parameters that have an override from Environment Variables will always override the provided value from the SPIRE configuration with the values in the environment.
>
> If all configuration parameters for the selected auth method are specified by environment variables, an empty block still must exist to select the auth method.
```hcl
UpstreamAuthority "ejbca" {
plugin_data {
hostname = "ejbca.example.com"
ca_cert_path = "/path/to/ca_cert.pem"
client_cert_path = "/path/to/client_cert.pem"
client_cert_key_path = "/path/to/client_key.pem"
ca_name = "Fake-Sub-CA"
end_entity_profile_name = "fakeSpireIntermediateCAEEP"
certificate_profile_name = "fakeSubCACP"
end_entity_name = "cn"
account_binding_id = "foo123"
}
}
```

## EJBCA Sub CA End Entity Profile & Certificate Profile Configuration

The connected EJBCA instance must have at least one Certificate Profile and at least one End Entity Profile capable of issuing SPIFFE certificates. The Certificate Profile must be of type `Sub CA`, and must be able to issue certificates with the ECDSA prime256v1 algorithm, at a minimum. The SPIRE Server configuration may require additional fields.

The End Entity Profile must have the following Subject DN Attributes:

* `serialNumber, Serial number (in DN)` [modifiable]
* `O, Organization` [modifiable]
* `C, Country (ISO 3166)` [modifiable]

And the following Other Subject Attributes:

* `Uniform Resource Identifier (URI)` [modifiable]

## EJBCA End Entity Name Customization (leaf certificates)

The EJBCA UpstreamAuthority plugin allows users to determine how the End Entity Name is selected at runtime. Here are the options you can use for `end_entity_name`:

* **`cn`:** Uses the Common Name from the CSR's Distinguished Name.
* **`dns`:** Uses the first DNS Name from the CSR's Subject Alternative Names (SANs).
* **`uri`:** Uses the first URI from the CSR's Subject Alternative Names (SANs).
* **`ip`:** Uses the first IP Address from the CSR's Subject Alternative Names (SANs).
* **Custom Value:** Any other string will be directly used as the End Entity Name.

By default, SPIRE issues certificates with no DN and only the SPIFFE ID in the SANs. If you want to use the SPIFFE ID as the End Entity Name, you can usually leave this field blank or set it to `uri`.

If the endEntityName field is not explicitly set, the EJBCA UpstreamAuthority plugin will attempt to determine the End Entity Name using the following default behavior:

* **First, it will try to use the Common Name:** It looks at the Common Name from the CSR's Distinguished Name.
* **If the Common Name is not available, it will use the first DNS Name:** It looks at the first DNS Name from the CSR's Subject Alternative Names (SANs).
* **If the DNS Name is not available, it will use the first URI:** It looks at the first URI from the CSR's Subject Alternative Names (SANs).
* **If the URI is not available, it will use the first IP Address:** It looks at the first IP Address from the CSR's Subject Alternative Names (SANs).
* **If none of the above are available, it will return an error.**
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0
github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.0
github.com/Keyfactor/ejbca-go-client-sdk v1.0.2
github.com/Microsoft/go-winio v0.6.2
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129
github.com/aws/aws-sdk-go-v2 v1.30.4
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dX
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.0 h1:gl5KGBBLKXc4BVKkyOJW9w6B890gUkoDkG/pYkTTQHE=
github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.0/go.mod h1:43xFPKNglOf/bHDR1DbcGTp4Erza2TiUJaU+X9L+1AI=
github.com/Keyfactor/ejbca-go-client-sdk v1.0.2 h1:pPnXCFfIFAwCjJrg1BtYlzoF8oHQ52sPOMs/uZ9uvZA=
github.com/Keyfactor/ejbca-go-client-sdk v1.0.2/go.mod h1:4Sv/KGVgRV4VXKko1ajfTaJwqJ5Aiw0VrDI9S7IcQ1g=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
Expand Down
2 changes: 2 additions & 0 deletions pkg/server/catalog/upstreamauthority.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/spiffe/spire/pkg/server/plugin/upstreamauthority/awssecret"
"github.com/spiffe/spire/pkg/server/plugin/upstreamauthority/certmanager"
"github.com/spiffe/spire/pkg/server/plugin/upstreamauthority/disk"
"github.com/spiffe/spire/pkg/server/plugin/upstreamauthority/ejbca"
"github.com/spiffe/spire/pkg/server/plugin/upstreamauthority/gcpcas"
spireplugin "github.com/spiffe/spire/pkg/server/plugin/upstreamauthority/spire"
"github.com/spiffe/spire/pkg/server/plugin/upstreamauthority/vault"
Expand Down Expand Up @@ -39,6 +40,7 @@ func (repo *upstreamAuthorityRepository) BuiltIns() []catalog.BuiltIn {
spireplugin.BuiltIn(),
disk.BuiltIn(),
certmanager.BuiltIn(),
ejbca.BuiltIn(),
}
}

Expand Down
Loading

0 comments on commit 7118533

Please sign in to comment.