Skip to content

Commit

Permalink
Pin UVM roots of trust and add snp_uvm_endorsements_file to configura…
Browse files Browse the repository at this point in the history
…tion (#5867)
  • Loading branch information
achamayou authored Dec 15, 2023
1 parent 085a22c commit 7b3f22f
Show file tree
Hide file tree
Showing 14 changed files with 90 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .snpcc_canary
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
(. =) Y (0 0) (x X) Y
O \ o | /
/-xXx--//-----x=x--/-xXx--/---x---->>>--/
...
......
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
[5.0.0-dev10]: https://github.com/microsoft/CCF/releases/tag/ccf-5.0.0-dev10

- The `url` field in `snp_endorsements_servers` can now contain environment variables that will be resolved at startup, such as "$Fabric_NodeIPOrFQDN:2377" (#5862).
- Add a `new snp_security_policy_file` configuration value under `attestation`, superseding the lookup from `$UVM_SECURITY_CONTEXT_DIR`. The value can contain environment variables, for example: `"snp_security_policy_file": "$UVM_SECURITY_CONTEXT_DIR/security-policy-base64"`.
- Add a new `snp_security_policy_file` configuration value under `attestation`, superseding the lookup from `$UVM_SECURITY_CONTEXT_DIR`. The value can contain environment variables, for example: `"snp_security_policy_file": "$UVM_SECURITY_CONTEXT_DIR/security-policy-base64"`.
- Add a new `snp_uvm_endorsements_file` configuration value under `attestation`, superseding the lookup from `$UVM_SECURITY_CONTEXT_DIR`. The value can contain environment variables, for example: `"snp_uvm_endorsements_file": "$UVM_SECURITY_CONTEXT_DIR/reference-info-base64"`. This value can come from an untrusted location, like `snp_security_policy_file` and AMD endorsements (fetched from `snp_endorsements_servers`), because the CCF code contains pre-defined roots of trust.

## [5.0.0-dev9]

Expand Down
4 changes: 4 additions & 0 deletions doc/host_config_schema/cchost_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@
"type": ["string", "null"],
"description": "Path to file containing the security policy (SEV-SNP only), can contain environment variables, such as $UVM_SECURITY_CONTEXT_DIR"
},
"snp_uvm_endorsements_file": {
"type": ["string", "null"],
"description": "Path to file containing UVM endorsements as a base64-encoded COSE Sign1 (SEV-SNP only). Can contain environment variables, such as $UVM_SECURITY_CONTEXT_DIR"
},
"snp_endorsements_servers": {
"type": "array",
"items": {
Expand Down
1 change: 1 addition & 0 deletions doc/operations/platforms/snp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ For non-Azure deployments, the certificate chain for VCEK will need to be retrie
}
],
"snp_security_policy_file": "/path/to/security-policy-base64",
"snp_uvm_endorsements_file": "/path/to/reference-info-base64"
}
.. tip:: See :ccf_repo:`samples/config/start_config_amd_sev_snp.json` for a sample node configuration for non-Azure deployments.
Expand Down
1 change: 1 addition & 0 deletions include/ccf/node/startup_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct CCFConfig
{
ccf::pal::snp::EndorsementsServers snp_endorsements_servers = {};
std::optional<std::string> snp_security_policy_file = std::nullopt;
std::optional<std::string> snp_uvm_endorsements_file = std::nullopt;

struct Environment
{
Expand Down
3 changes: 2 additions & 1 deletion samples/config/start_config_aci_sev_snp.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"url": "169.254.169.254"
}
],
"snp_security_policy_file": "$UVM_SECURITY_CONTEXT_DIR/security-policy-base64"
"snp_security_policy_file": "$UVM_SECURITY_CONTEXT_DIR/security-policy-base64",
"snp_uvm_endorsements_file": "$UVM_SECURITY_CONTEXT_DIR/reference-info-base64"
}
}
11 changes: 8 additions & 3 deletions samples/config/start_config_aks_sev_snp.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@
}
},
"attestation": {
"environment": {
"security_context_directory": "UVM_SECURITY_CONTEXT_DIR"
}
"snp_endorsements_servers": [
{
"type": "THIM",
"url": "169.254.169.254"
}
],
"snp_security_policy_file": "/path/to/security-policy-base64",
"snp_uvm_endorsements_file": "/opt/confidential-containers/share/kata-containers/reference-info-base64"
}
}
3 changes: 2 additions & 1 deletion samples/config/start_config_amd_sev_snp.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"url": "kdsintf.amd.com"
}
],
"snp_security_policy_file": "/path/to/security-policy-base64"
"snp_security_policy_file": "/path/to/security-policy-base64",
"snp_uvm_endorsements_file": "/path/to/reference-info-base64"
}
}
3 changes: 2 additions & 1 deletion src/common/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ DECLARE_JSON_OPTIONAL_FIELDS(
CCFConfig::Attestation,
snp_endorsements_servers,
environment,
snp_security_policy_file);
snp_security_policy_file,
snp_uvm_endorsements_file);

DECLARE_JSON_TYPE_WITH_OPTIONAL_FIELDS(CCFConfig);
DECLARE_JSON_REQUIRED_FIELDS(CCFConfig, network);
Expand Down
15 changes: 15 additions & 0 deletions src/host/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,21 @@ int main(int argc, char** argv)
files::try_slurp_string(security_policy_file);
}

if (startup_config.attestation.snp_uvm_endorsements_file.has_value())
{
auto snp_uvm_endorsements_file =
startup_config.attestation.snp_uvm_endorsements_file.value();
LOG_DEBUG_FMT(
"Resolving snp_uvm_endorsements_file: {}", snp_uvm_endorsements_file);
snp_uvm_endorsements_file =
nonstd::expand_envvars_in_path(snp_uvm_endorsements_file);
LOG_DEBUG_FMT(
"Resolved snp_uvm_endorsements_file: {}", snp_uvm_endorsements_file);

startup_config.attestation.environment.uvm_endorsements =
files::try_slurp_string(snp_uvm_endorsements_file);
}

for (auto endorsement_servers_it =
startup_config.attestation.snp_endorsements_servers.begin();
endorsement_servers_it !=
Expand Down
42 changes: 41 additions & 1 deletion src/node/uvm_endorsements.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,34 @@ namespace ccf
std::string feed;
};

// Roots of trust for UVM endorsements/measurement in AMD SEV-SNP attestations
static std::vector<UVMEndorsements> uvm_roots_of_trust = {
// Confidential Azure Kubertnetes Service (AKS)
{"did:x509:0:sha256:I__iuL25oXEVFdTP_aBLx_eT1RPHbCQ_ECBQfYZpt9s::eku:1.3.6."
"1.4.1.311.76.59.1.2",
"ContainerPlat-AMD-UVM",
"0"},
// Confidential Azure Container Instances (ACI)
{"did:x509:0:sha256:I__iuL25oXEVFdTP_aBLx_eT1RPHbCQ_ECBQfYZpt9s::eku:1.3.6."
"1.4.1.311.76.59.1.5",
"ConfAKS-AMD-UVM",
"0"}};

bool inline matches_uvm_roots_of_trust(const UVMEndorsements& endorsements)
{
for (const auto& uvm_root_of_trust : uvm_roots_of_trust)
{
if (
uvm_root_of_trust.did == endorsements.did &&
uvm_root_of_trust.feed == endorsements.feed &&
uvm_root_of_trust.svn <= endorsements.svn)
{
return true;
}
}
return false;
}

namespace cose
{
static constexpr auto HEADER_PARAM_ISSUER = "iss";
Expand Down Expand Up @@ -311,6 +339,18 @@ namespace ccf
phdr.feed,
payload.sevsnpvm_guest_svn);

return {did, phdr.feed, payload.sevsnpvm_guest_svn};
UVMEndorsements end{did, phdr.feed, payload.sevsnpvm_guest_svn};

if (!matches_uvm_roots_of_trust(end))
{
throw std::logic_error(fmt::format(
"UVM endorsements did {}, feed {}, svn {} "
"do not match any of the known UVM roots of trust",
end.did,
end.feed,
end.svn));
}

return end;
}
}
3 changes: 2 additions & 1 deletion tests/config.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"attestation":
{
"snp_endorsements_servers": {{ snp_endorsements_servers|tojson }},
"snp_security_policy_file": "{{ snp_security_policy_file }}"
"snp_security_policy_file": "{{ snp_security_policy_file }}",
"snp_uvm_endorsements_file": "{{ snp_uvm_endorsements_file }}"
},
"service_data_json_file": {{ service_data_json_file|tojson }},
"command": {
Expand Down
1 change: 1 addition & 0 deletions tests/infra/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class Network:
"tick_ms",
"max_msg_size_bytes",
"snp_security_policy_file",
"snp_uvm_endorsements_file",
]

# Maximum delay (seconds) for updates to propagate from the primary to backups
Expand Down
8 changes: 8 additions & 0 deletions tests/infra/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ def __init__(
follow_redirect=True,
max_uncommitted_tx_count=0,
snp_security_policy_file=None,
snp_uvm_endorsements_file=None,
**kwargs,
):
"""
Expand Down Expand Up @@ -742,6 +743,12 @@ def __init__(
"$UVM_SECURITY_CONTEXT_DIR/security-policy-base64"
)

# Default snp_uvm_endorsements_file if not set
if snp_uvm_endorsements_file is None:
snp_uvm_endorsements_file = (
"$UVM_SECURITY_CONTEXT_DIR/reference-info-base64"
)

# Validate consensus timers
if (
election_timeout_ms is not None
Expand Down Expand Up @@ -803,6 +810,7 @@ def __init__(
follow_redirect=follow_redirect,
max_uncommitted_tx_count=max_uncommitted_tx_count,
snp_security_policy_file=snp_security_policy_file,
snp_uvm_endorsements_file=snp_uvm_endorsements_file,
**kwargs,
)

Expand Down

0 comments on commit 7b3f22f

Please sign in to comment.