// The Connect certificate authority: the roots an agent trusts, the leaf
// certificate an agent issues for a service, and the cluster-wide CA
// configuration. A leaf's identity is its SPIFFE URI, which is what a proxy
// presents and what `Agent::connect_authorize` decides on.
///|
/// One trusted root certificate of the Connect CA.
pub(all) struct CARoot {
/// The root's globally unique id, also its certificate serial in hex.
id : String
/// A human-friendly name; Consul does not interpret it.
name : String
/// The certificate serial number.
serial_number : UInt64
/// The id of the key that signed this root.
signing_key_id : String
/// The trust domain of the Consul cluster that owns the root.
external_trust_domain : String
/// The start of the root's validity, as the agent reports it.
not_before : String?
/// The end of the root's validity.
not_after : String?
/// The PEM-encoded root certificate.
root_cert_pem : String
/// The PEM-encoded intermediates between the root and a leaf, if any.
intermediate_cert_pems : Array[String]
/// Whether this is the root the CA signs with now.
active : Bool
/// The key type, e.g. `ec`.
private_key_type : String?
/// The key size in bits.
private_key_bits : Int32?
create_index : UInt64
modify_index : UInt64
}
///|
/// The roots an agent trusts: the active root's id, the trust domain every
/// SPIFFE identity of the cluster sits under, and the roots themselves.
pub(all) struct CARoots {
active_root_id : String
trust_domain : String
roots : Array[CARoot]
}
///|
/// A leaf certificate the CA issued for one service: the PEM certificate and
/// key, and the SPIFFE identity they carry.
pub(all) struct LeafCert {
/// The serial number in hex, colon-separated.
serial_number : String
/// The PEM-encoded certificate.
cert_pem : String
/// The PEM-encoded private key.
private_key_pem : String
/// The service the certificate was issued for.
service : String
/// The SPIFFE identity in the certificate, e.g.
/// `spiffe:///ns/default/dc/dc1/svc/web`.
service_uri : String
/// The start of the certificate's validity.
valid_after : String?
/// The end of the certificate's validity.
valid_before : String?
create_index : UInt64
modify_index : UInt64
}
///|
/// The cluster-wide Connect CA configuration: the provider that signs, its
/// arbitrary settings, and the read-only state the provider persisted.
pub(all) struct CAConfig {
/// The CA provider, e.g. `consul` or `vault`.
provider : String
/// Provider settings, held as the JSON the agent serves so that any
/// provider's shape round-trips.
config : Map[String, Json]?
/// State the provider persisted; the agent sets it and rejects it on a write.
state : Map[String, String]?
/// Reconfigure even when the current CA cannot cross-sign, accepting that
/// proxies may reject the new leaves until they see the new root.
force_without_cross_signing : Bool
create_index : UInt64
modify_index : UInt64
}
///|
/// A CA configuration for `provider`, with no settings and cross-signing
/// required.
pub fn CAConfig::new(provider : String) -> CAConfig {
{
provider,
config: None,
state: None,
force_without_cross_signing: false,
create_index: 0UL,
modify_index: 0UL,
}
}
///|
/// The parameters of an authorization decision: the service a connection is
/// headed for, and the SPIFFE identity and serial the client presented.
pub(all) struct AgentAuthorizeParams {
/// The destination service name.
target : String
/// The client certificate's SPIFFE URI.
client_cert_uri : String
/// The client certificate's serial number.
client_cert_serial : String
}
///|
/// The answer to an authorization request, with the agent's reason.
pub(all) struct AgentAuthorize {
authorized : Bool
reason : String
}
///|
/// A `CARoot` from its JSON object.
fn caroot_of(j : Json) -> CARoot {
let m = json_map(j)
let intermediates : Array[String] = []
for item in jarray(m, "IntermediateCerts") {
if item is String(s) {
intermediates.push(s)
}
}
{
id: jstr(m, "ID"),
name: jstr(m, "Name"),
serial_number: ju64(m, "SerialNumber"),
signing_key_id: jstr(m, "SigningKeyID"),
external_trust_domain: jstr(m, "ExternalTrustDomain"),
not_before: jstr_opt(m, "NotBefore"),
not_after: jstr_opt(m, "NotAfter"),
root_cert_pem: jstr(m, "RootCert"),
intermediate_cert_pems: intermediates,
active: jbool(m, "Active"),
private_key_type: jstr_opt(m, "PrivateKeyType"),
private_key_bits: ji32_opt(m, "PrivateKeyBits"),
create_index: ju64(m, "CreateIndex"),
modify_index: ju64(m, "ModifyIndex"),
}
}
///|
/// A `CARoots` from its JSON object.
fn caroots_of(j : Json) -> CARoots {
let m = json_map(j)
let roots : Array[CARoot] = []
for item in jarray(m, "Roots") {
roots.push(caroot_of(item))
}
{
active_root_id: jstr(m, "ActiveRootID"),
trust_domain: jstr(m, "TrustDomain"),
roots,
}
}
///|
/// A `LeafCert` from its JSON object.
fn leaf_cert_of(j : Json) -> LeafCert {
let m = json_map(j)
{
serial_number: jstr(m, "SerialNumber"),
cert_pem: jstr(m, "CertPEM"),
private_key_pem: jstr(m, "PrivateKeyPEM"),
service: jstr(m, "Service"),
service_uri: jstr(m, "ServiceURI"),
valid_after: jstr_opt(m, "ValidAfter"),
valid_before: jstr_opt(m, "ValidBefore"),
create_index: ju64(m, "CreateIndex"),
modify_index: ju64(m, "ModifyIndex"),
}
}
///|
/// A `CAConfig` from its JSON object.
fn ca_config_of(j : Json) -> CAConfig {
let m = json_map(j)
{
provider: jstr(m, "Provider"),
config: jobj_opt(m, "Config"),
state: jmap_opt(m, "State"),
force_without_cross_signing: jbool(m, "ForceWithoutCrossSigning"),
create_index: ju64(m, "CreateIndex"),
modify_index: ju64(m, "ModifyIndex"),
}
}
///|
/// A `CAConfig` as its write body. `state` is left out: the agent writes it and
/// rejects a configuration that carries one.
fn ca_config_to_json(c : CAConfig) -> Json {
let m = jobj()
put_str(m, "Provider", Some(c.provider))
m["Config"] = Json::object(
match c.config {
Some(cf) => cf
None => Map([])
},
)
put_bool(m, "ForceWithoutCrossSigning", Some(c.force_without_cross_signing))
Json::object(m)
}
///|
/// An `AgentAuthorizeParams` as its request body.
fn agent_authorize_params_to_json(p : AgentAuthorizeParams) -> Json {
let m = jobj()
put_str(m, "Target", Some(p.target))
put_str(m, "ClientCertURI", Some(p.client_cert_uri))
put_str(m, "ClientCertSerial", Some(p.client_cert_serial))
Json::object(m)
}
///|
/// An `AgentAuthorize` from its JSON object.
fn agent_authorize_of(j : Json) -> AgentAuthorize {
let m = json_map(j)
{ authorized: jbool(m, "Authorized"), reason: jstr(m, "Reason"), }
}