mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-06-19 11:44:20 -04:00
attestation: add option for MAA fallback to verify azure's snp-sev id key digest (#1257)
* Convert enforceIDKeyDigest setting to enum * Use MAA fallback in Azure SNP attestation * Only create MAA provider if MAA fallback is enabled --------- Signed-off-by: Daniel Weiße <dw@edgeless.systems> Co-authored-by: Thomas Tendyck <tt@edgeless.systems>
This commit is contained in:
parent
9a9688583d
commit
5a0234b3f2
66 changed files with 1073 additions and 542 deletions
|
@ -1718,6 +1718,15 @@ def go_dependencies():
|
||||||
sum = "h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=",
|
sum = "h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=",
|
||||||
version = "v1.1.0",
|
version = "v1.1.0",
|
||||||
)
|
)
|
||||||
|
go_repository(
|
||||||
|
name = "com_github_edgelesssys_go_azguestattestation",
|
||||||
|
build_file_generation = "on",
|
||||||
|
build_file_proto_mode = "disable_global",
|
||||||
|
importpath = "github.com/edgelesssys/go-azguestattestation",
|
||||||
|
sum = "h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=",
|
||||||
|
version = "v0.0.0-20230303085714-62ede861d33f",
|
||||||
|
)
|
||||||
|
|
||||||
go_repository(
|
go_repository(
|
||||||
name = "com_github_edsrzf_mmap_go",
|
name = "com_github_edsrzf_mmap_go",
|
||||||
build_file_generation = "on",
|
build_file_generation = "on",
|
||||||
|
@ -2724,8 +2733,9 @@ def go_dependencies():
|
||||||
build_file_generation = "on",
|
build_file_generation = "on",
|
||||||
build_file_proto_mode = "disable_global",
|
build_file_proto_mode = "disable_global",
|
||||||
importpath = "github.com/google/go-tpm",
|
importpath = "github.com/google/go-tpm",
|
||||||
sum = "h1:P/ZFNBZYXRxc+z7i5uyd8VP7MaDteuLZInzrH2idRGo=",
|
replace = "github.com/thomasten/go-tpm",
|
||||||
version = "v0.3.3",
|
sum = "h1:4/WcA7Q05f5to+jVERKcZjU5NJ89DiRHP3UUZHLfAtw=",
|
||||||
|
version = "v0.0.0-20230222180349-bb3cc5560299",
|
||||||
)
|
)
|
||||||
go_repository(
|
go_repository(
|
||||||
name = "com_github_google_go_tpm_tools",
|
name = "com_github_google_go_tpm_tools",
|
||||||
|
|
|
@ -37,7 +37,7 @@ type InitRequest struct {
|
||||||
// bytes salt = 10; removed
|
// bytes salt = 10; removed
|
||||||
HelmDeployments []byte `protobuf:"bytes,11,opt,name=helm_deployments,json=helmDeployments,proto3" json:"helm_deployments,omitempty"`
|
HelmDeployments []byte `protobuf:"bytes,11,opt,name=helm_deployments,json=helmDeployments,proto3" json:"helm_deployments,omitempty"`
|
||||||
EnforcedPcrs []uint32 `protobuf:"varint,12,rep,packed,name=enforced_pcrs,json=enforcedPcrs,proto3" json:"enforced_pcrs,omitempty"`
|
EnforcedPcrs []uint32 `protobuf:"varint,12,rep,packed,name=enforced_pcrs,json=enforcedPcrs,proto3" json:"enforced_pcrs,omitempty"`
|
||||||
EnforceIdkeydigest bool `protobuf:"varint,13,opt,name=enforce_idkeydigest,json=enforceIdkeydigest,proto3" json:"enforce_idkeydigest,omitempty"`
|
// bool enforce_idkeydigest = 13; removed
|
||||||
ConformanceMode bool `protobuf:"varint,14,opt,name=conformance_mode,json=conformanceMode,proto3" json:"conformance_mode,omitempty"`
|
ConformanceMode bool `protobuf:"varint,14,opt,name=conformance_mode,json=conformanceMode,proto3" json:"conformance_mode,omitempty"`
|
||||||
KubernetesComponents []*KubernetesComponent `protobuf:"bytes,15,rep,name=kubernetes_components,json=kubernetesComponents,proto3" json:"kubernetes_components,omitempty"`
|
KubernetesComponents []*KubernetesComponent `protobuf:"bytes,15,rep,name=kubernetes_components,json=kubernetesComponents,proto3" json:"kubernetes_components,omitempty"`
|
||||||
InitSecret []byte `protobuf:"bytes,16,opt,name=init_secret,json=initSecret,proto3" json:"init_secret,omitempty"`
|
InitSecret []byte `protobuf:"bytes,16,opt,name=init_secret,json=initSecret,proto3" json:"init_secret,omitempty"`
|
||||||
|
@ -118,13 +118,6 @@ func (x *InitRequest) GetEnforcedPcrs() []uint32 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *InitRequest) GetEnforceIdkeydigest() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.EnforceIdkeydigest
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitRequest) GetConformanceMode() bool {
|
func (x *InitRequest) GetConformanceMode() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ConformanceMode
|
return x.ConformanceMode
|
||||||
|
@ -291,7 +284,7 @@ var File_init_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_init_proto_rawDesc = []byte{
|
var file_init_proto_rawDesc = []byte{
|
||||||
0x0a, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x69, 0x6e,
|
0x0a, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x69, 0x6e,
|
||||||
0x69, 0x74, 0x22, 0xf1, 0x03, 0x0a, 0x0b, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
|
0x69, 0x74, 0x22, 0xc0, 0x03, 0x0a, 0x0b, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||||
0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x6d, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x03, 0x20,
|
0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6b, 0x6d, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x03, 0x20,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x6b, 0x6d, 0x73, 0x55, 0x72, 0x69, 0x12, 0x1f, 0x0a, 0x0b, 0x73,
|
0x01, 0x28, 0x09, 0x52, 0x06, 0x6b, 0x6d, 0x73, 0x55, 0x72, 0x69, 0x12, 0x1f, 0x0a, 0x0b, 0x73,
|
||||||
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
||||||
|
@ -307,44 +300,41 @@ var file_init_proto_rawDesc = []byte{
|
||||||
0x52, 0x0f, 0x68, 0x65, 0x6c, 0x6d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74,
|
0x52, 0x0f, 0x68, 0x65, 0x6c, 0x6d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74,
|
||||||
0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x5f, 0x70, 0x63,
|
0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x5f, 0x70, 0x63,
|
||||||
0x72, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63,
|
0x72, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63,
|
||||||
0x65, 0x64, 0x50, 0x63, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63,
|
0x65, 0x64, 0x50, 0x63, 0x72, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72,
|
||||||
0x65, 0x5f, 0x69, 0x64, 0x6b, 0x65, 0x79, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x0d, 0x20,
|
0x6d, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08,
|
||||||
0x01, 0x28, 0x08, 0x52, 0x12, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x49, 0x64, 0x6b, 0x65,
|
0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x6f, 0x64,
|
||||||
0x79, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x6f,
|
0x65, 0x12, 0x4e, 0x0a, 0x15, 0x6b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x5f,
|
||||||
0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28,
|
0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x08, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x4d, 0x6f,
|
0x32, 0x19, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||||
0x64, 0x65, 0x12, 0x4e, 0x0a, 0x15, 0x6b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73,
|
0x65, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x14, 0x6b, 0x75, 0x62,
|
||||||
0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28,
|
0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
|
||||||
0x0b, 0x32, 0x19, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65,
|
0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74,
|
||||||
0x74, 0x65, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x14, 0x6b, 0x75,
|
0x18, 0x10, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x53, 0x65, 0x63, 0x72,
|
||||||
0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
|
0x65, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61,
|
||||||
0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65,
|
0x6d, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
|
||||||
0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x53, 0x65, 0x63,
|
0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x68, 0x0a, 0x0c, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73,
|
||||||
0x72, 0x65, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e,
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6b, 0x75, 0x62, 0x65, 0x63, 0x6f, 0x6e,
|
||||||
0x61, 0x6d, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74,
|
0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6b, 0x75, 0x62, 0x65, 0x63,
|
||||||
0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x68, 0x0a, 0x0c, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6b, 0x75, 0x62, 0x65, 0x63, 0x6f,
|
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64,
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6b, 0x75, 0x62, 0x65,
|
0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03,
|
||||||
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f,
|
0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22,
|
||||||
0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49,
|
0x78, 0x0a, 0x13, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6d,
|
||||||
0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
|
0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20,
|
||||||
0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64,
|
0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68,
|
||||||
0x22, 0x78, 0x0a, 0x13, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6f,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c,
|
||||||
0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01,
|
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73,
|
0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12,
|
||||||
0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a,
|
0x18, 0x0a, 0x07, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
|
||||||
0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20,
|
0x52, 0x07, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x32, 0x34, 0x0a, 0x03, 0x41, 0x50, 0x49,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x50, 0x61, 0x74, 0x68,
|
0x12, 0x2d, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x11, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2e,
|
||||||
0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
|
0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x69, 0x6e,
|
||||||
0x08, 0x52, 0x07, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x32, 0x34, 0x0a, 0x03, 0x41, 0x50,
|
0x69, 0x74, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42,
|
||||||
0x49, 0x12, 0x2d, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x11, 0x2e, 0x69, 0x6e, 0x69, 0x74,
|
0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x64,
|
||||||
0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x69,
|
0x67, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x73, 0x79, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x65,
|
||||||
0x6e, 0x69, 0x74, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x32, 0x2f, 0x62, 0x6f, 0x6f, 0x74, 0x73,
|
||||||
0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65,
|
0x74, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x69, 0x74, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x64, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x73, 0x79, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x74,
|
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x32, 0x2f, 0x62, 0x6f, 0x6f, 0x74,
|
|
||||||
0x73, 0x74, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x69, 0x74, 0x70, 0x72, 0x6f,
|
|
||||||
0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -21,7 +21,7 @@ message InitRequest {
|
||||||
// bytes salt = 10; removed
|
// bytes salt = 10; removed
|
||||||
bytes helm_deployments = 11;
|
bytes helm_deployments = 11;
|
||||||
repeated uint32 enforced_pcrs = 12;
|
repeated uint32 enforced_pcrs = 12;
|
||||||
bool enforce_idkeydigest = 13;
|
// bool enforce_idkeydigest = 13; removed
|
||||||
bool conformance_mode = 14;
|
bool conformance_mode = 14;
|
||||||
repeated KubernetesComponent kubernetes_components = 15;
|
repeated KubernetesComponent kubernetes_components = 15;
|
||||||
bytes init_secret = 16;
|
bytes init_secret = 16;
|
||||||
|
|
|
@ -81,9 +81,8 @@ func New(cloudProvider string, clusterUtil clusterUtil, configProvider configura
|
||||||
|
|
||||||
// InitCluster initializes a new Kubernetes cluster and applies pod network provider.
|
// InitCluster initializes a new Kubernetes cluster and applies pod network provider.
|
||||||
func (k *KubeWrapper) InitCluster(
|
func (k *KubeWrapper) InitCluster(
|
||||||
ctx context.Context, cloudServiceAccountURI, versionString, clusterName string,
|
ctx context.Context, cloudServiceAccountURI, versionString, clusterName string, measurementSalt []byte, enforcedPCRs []uint32,
|
||||||
measurementSalt []byte, enforcedPCRs []uint32, helmReleasesRaw []byte, conformanceMode bool,
|
helmReleasesRaw []byte, conformanceMode bool, kubernetesComponents components.Components, log *logger.Logger,
|
||||||
kubernetesComponents components.Components, log *logger.Logger,
|
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
log.With(zap.String("version", versionString)).Infof("Installing Kubernetes components")
|
log.With(zap.String("version", versionString)).Infof("Installing Kubernetes components")
|
||||||
if err := k.clusterUtil.InstallComponents(ctx, kubernetesComponents); err != nil {
|
if err := k.clusterUtil.InstallComponents(ctx, kubernetesComponents); err != nil {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/image"
|
"github.com/edgelesssys/constellation/v2/cli/internal/image"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
|
"github.com/edgelesssys/constellation/v2/cli/internal/libvirt"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
|
@ -206,7 +207,7 @@ func (c *Creator) createAzure(ctx context.Context, cl terraformClient, config *c
|
||||||
ImageID: image,
|
ImageID: image,
|
||||||
ConfidentialVM: *config.Provider.Azure.ConfidentialVM,
|
ConfidentialVM: *config.Provider.Azure.ConfidentialVM,
|
||||||
SecureBoot: *config.Provider.Azure.SecureBoot,
|
SecureBoot: *config.Provider.Azure.SecureBoot,
|
||||||
CreateMAA: *config.Provider.Azure.EnforceIDKeyDigest,
|
CreateMAA: config.Provider.Azure.EnforceIDKeyDigest == idkeydigest.MAAFallback,
|
||||||
Debug: config.IsDebugCluster(),
|
Debug: config.IsDebugCluster(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,14 +26,13 @@ import (
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
attestationVariant oid.Getter
|
attestationVariant oid.Getter
|
||||||
pcrs measurements.M
|
pcrs measurements.M
|
||||||
idkeydigests idkeydigest.IDKeyDigests
|
idKeyConfig idkeydigest.Config
|
||||||
enforceIDKeyDigest bool
|
|
||||||
validator atls.Validator
|
validator atls.Validator
|
||||||
log debugLog
|
log debugLog
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator creates a new Validator.
|
// NewValidator creates a new Validator.
|
||||||
func NewValidator(conf *config.Config, log debugLog) (*Validator, error) {
|
func NewValidator(conf *config.Config, maaURL string, log debugLog) (*Validator, error) {
|
||||||
v := Validator{log: log}
|
v := Validator{log: log}
|
||||||
variant, err := oid.FromString(conf.AttestationVariant)
|
variant, err := oid.FromString(conf.AttestationVariant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -46,8 +45,11 @@ func NewValidator(conf *config.Config, log debugLog) (*Validator, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.attestationVariant.OID().Equal(oid.AzureSEVSNP{}.OID()) {
|
if v.attestationVariant.OID().Equal(oid.AzureSEVSNP{}.OID()) {
|
||||||
v.enforceIDKeyDigest = conf.EnforcesIDKeyDigest()
|
v.idKeyConfig = idkeydigest.Config{
|
||||||
v.idkeydigests = conf.IDKeyDigests()
|
IDKeyDigests: conf.Provider.Azure.IDKeyDigest,
|
||||||
|
EnforcementPolicy: conf.IDKeyDigestPolicy(),
|
||||||
|
MAAURL: maaURL,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v, nil
|
return &v, nil
|
||||||
|
@ -138,7 +140,7 @@ func (v *Validator) updateValidator(cmd *cobra.Command) {
|
||||||
log := warnLogger{cmd: cmd, log: v.log}
|
log := warnLogger{cmd: cmd, log: v.log}
|
||||||
|
|
||||||
// Use of a valid variant has been check in NewValidator so we may drop the error
|
// Use of a valid variant has been check in NewValidator so we may drop the error
|
||||||
v.validator, _ = choose.Validator(v.attestationVariant, v.pcrs, v.idkeydigests, v.enforceIDKeyDigest, log)
|
v.validator, _ = choose.Validator(v.attestationVariant, v.pcrs, v.idKeyConfig, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// warnLogger implements logging of warnings for validators.
|
// warnLogger implements logging of warnings for validators.
|
||||||
|
|
|
@ -110,7 +110,7 @@ func TestNewValidator(t *testing.T) {
|
||||||
Azure: &config.AzureConfig{
|
Azure: &config.AzureConfig{
|
||||||
Measurements: testPCRs,
|
Measurements: testPCRs,
|
||||||
IDKeyDigest: idkeydigest.IDKeyDigests{[]byte("414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141")},
|
IDKeyDigest: idkeydigest.IDKeyDigests{[]byte("414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141")},
|
||||||
EnforceIDKeyDigest: &[]bool{true}[0],
|
EnforceIDKeyDigest: idkeydigest.StrictChecking,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -121,7 +121,7 @@ func TestNewValidator(t *testing.T) {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
validators, err := NewValidator(tc.config, logger.NewTest(t))
|
validators, err := NewValidator(tc.config, "https://192.0.2.1:8080/maa", logger.NewTest(t))
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
@ -168,7 +168,11 @@ func TestValidatorV(t *testing.T) {
|
||||||
"azure cvm": {
|
"azure cvm": {
|
||||||
variant: oid.AzureSEVSNP{},
|
variant: oid.AzureSEVSNP{},
|
||||||
pcrs: newTestPCRs(),
|
pcrs: newTestPCRs(),
|
||||||
wantVs: snp.NewValidator(newTestPCRs(), idkeydigest.IDKeyDigests{}, false, nil),
|
wantVs: snp.NewValidator(
|
||||||
|
newTestPCRs(),
|
||||||
|
idkeydigest.Config{IDKeyDigests: idkeydigest.IDKeyDigests{}, EnforcementPolicy: idkeydigest.WarnOnly},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
"azure trusted launch": {
|
"azure trusted launch": {
|
||||||
variant: oid.AzureTrustedLaunch{},
|
variant: oid.AzureTrustedLaunch{},
|
||||||
|
|
|
@ -43,6 +43,7 @@ go_library(
|
||||||
"//cli/internal/terraform",
|
"//cli/internal/terraform",
|
||||||
"//disk-mapper/recoverproto",
|
"//disk-mapper/recoverproto",
|
||||||
"//internal/atls",
|
"//internal/atls",
|
||||||
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/azureshared",
|
"//internal/cloud/azureshared",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
|
@ -97,8 +98,8 @@ func (c *createCmd) create(cmd *cobra.Command, creator cloudCreator, fileHandler
|
||||||
if conf.IsAzureNonCVM() {
|
if conf.IsAzureNonCVM() {
|
||||||
cmd.PrintErrln("Disabling Confidential VMs is insecure. Use only for evaluation purposes.")
|
cmd.PrintErrln("Disabling Confidential VMs is insecure. Use only for evaluation purposes.")
|
||||||
printedAWarning = true
|
printedAWarning = true
|
||||||
if conf.EnforcesIDKeyDigest() {
|
if conf.IDKeyDigestPolicy() == idkeydigest.StrictChecking || conf.IDKeyDigestPolicy() == idkeydigest.MAAFallback {
|
||||||
cmd.PrintErrln("Your config asks for enforcing the idkeydigest. This is only available on Confidential VMs. It will not be enforced.")
|
cmd.PrintErrln("Your config asks for validating the idkeydigest. This is only available on Confidential VMs. It will not be enforced.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,9 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator *cloud
|
||||||
cmd.PrintErrf("License check failed: %v", err)
|
cmd.PrintErrf("License check failed: %v", err)
|
||||||
}
|
}
|
||||||
i.log.Debugf("Checked license")
|
i.log.Debugf("Checked license")
|
||||||
validator, err := cloudcmd.NewValidator(conf, i.log)
|
|
||||||
|
i.log.Debugf("Creating aTLS Validator for %s", conf.AttestationVariant)
|
||||||
|
validator, err := cloudcmd.NewValidator(conf, idFile.AttestationURL, i.log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -153,7 +155,7 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator *cloud
|
||||||
}
|
}
|
||||||
helmLoader := helm.NewLoader(provider, k8sVersion)
|
helmLoader := helm.NewLoader(provider, k8sVersion)
|
||||||
i.log.Debugf("Created new Helm loader")
|
i.log.Debugf("Created new Helm loader")
|
||||||
helmDeployments, err := helmLoader.Load(conf, flags.conformance, masterSecret.Key, masterSecret.Salt)
|
helmDeployments, err := helmLoader.Load(conf, flags.conformance, masterSecret.Key, masterSecret.Salt, idFile.AttestationURL)
|
||||||
i.log.Debugf("Loaded Helm deployments")
|
i.log.Debugf("Loaded Helm deployments")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("loading Helm charts: %w", err)
|
return fmt.Errorf("loading Helm charts: %w", err)
|
||||||
|
@ -172,7 +174,6 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator *cloud
|
||||||
KubernetesComponents: versions.VersionConfigs[k8sVersion].KubernetesComponents.ToInitProto(),
|
KubernetesComponents: versions.VersionConfigs[k8sVersion].KubernetesComponents.ToInitProto(),
|
||||||
HelmDeployments: helmDeployments,
|
HelmDeployments: helmDeployments,
|
||||||
EnforcedPcrs: conf.EnforcedPCRs(),
|
EnforcedPcrs: conf.EnforcedPCRs(),
|
||||||
EnforceIdkeydigest: conf.EnforcesIDKeyDigest(),
|
|
||||||
ConformanceMode: flags.conformance,
|
ConformanceMode: flags.conformance,
|
||||||
InitSecret: idFile.InitSecret,
|
InitSecret: idFile.InitSecret,
|
||||||
ClusterName: clusterName,
|
ClusterName: clusterName,
|
||||||
|
@ -426,17 +427,6 @@ func (i *initCmd) readOrGenerateMasterSecret(outWriter io.Writer, fileHandler fi
|
||||||
return secret, nil
|
return secret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readIPFromIDFile(fileHandler file.Handler) (string, error) {
|
|
||||||
var idFile clusterid.File
|
|
||||||
if err := fileHandler.ReadJSON(constants.ClusterIDsFileName, &idFile); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if idFile.IP == "" {
|
|
||||||
return "", fmt.Errorf("missing IP address in %q", constants.ClusterIDsFileName)
|
|
||||||
}
|
|
||||||
return idFile.IP, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *initCmd) getMarshaledServiceAccountURI(provider cloudprovider.Provider, config *config.Config, fileHandler file.Handler) (string, error) {
|
func (i *initCmd) getMarshaledServiceAccountURI(provider cloudprovider.Provider, config *config.Config, fileHandler file.Handler) (string, error) {
|
||||||
i.log.Debugf("Getting service account URI")
|
i.log.Debugf("Getting service account URI")
|
||||||
switch provider {
|
switch provider {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
"github.com/edgelesssys/constellation/v2/cli/internal/cloudcmd"
|
||||||
|
"github.com/edgelesssys/constellation/v2/cli/internal/clusterid"
|
||||||
"github.com/edgelesssys/constellation/v2/disk-mapper/recoverproto"
|
"github.com/edgelesssys/constellation/v2/disk-mapper/recoverproto"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -95,7 +96,8 @@ func (r *recoverCmd) recover(
|
||||||
interval = 20 * time.Second // Azure LB takes a while to remove unhealthy instances
|
interval = 20 * time.Second // Azure LB takes a while to remove unhealthy instances
|
||||||
}
|
}
|
||||||
|
|
||||||
validator, err := cloudcmd.NewValidator(conf, r.log)
|
r.log.Debugf("Creating aTLS Validator for %s", conf.AttestationVariant)
|
||||||
|
validator, err := cloudcmd.NewValidator(conf, flags.maaURL, r.log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -208,20 +210,23 @@ type recoverFlags struct {
|
||||||
endpoint string
|
endpoint string
|
||||||
secretPath string
|
secretPath string
|
||||||
configPath string
|
configPath string
|
||||||
|
maaURL string
|
||||||
force bool
|
force bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *recoverCmd) parseRecoverFlags(cmd *cobra.Command, fileHandler file.Handler) (recoverFlags, error) {
|
func (r *recoverCmd) parseRecoverFlags(cmd *cobra.Command, fileHandler file.Handler) (recoverFlags, error) {
|
||||||
|
var idFile clusterid.File
|
||||||
|
if err := fileHandler.ReadJSON(constants.ClusterIDsFileName, &idFile); err != nil && !errors.Is(err, afero.ErrFileNotFound) {
|
||||||
|
return recoverFlags{}, err
|
||||||
|
}
|
||||||
|
|
||||||
endpoint, err := cmd.Flags().GetString("endpoint")
|
endpoint, err := cmd.Flags().GetString("endpoint")
|
||||||
r.log.Debugf("Endpoint flag is %s", endpoint)
|
r.log.Debugf("Endpoint flag is %s", endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return recoverFlags{}, fmt.Errorf("parsing endpoint argument: %w", err)
|
return recoverFlags{}, fmt.Errorf("parsing endpoint argument: %w", err)
|
||||||
}
|
}
|
||||||
if endpoint == "" {
|
if endpoint == "" {
|
||||||
endpoint, err = readIPFromIDFile(fileHandler)
|
endpoint = idFile.IP
|
||||||
if err != nil {
|
|
||||||
return recoverFlags{}, fmt.Errorf("getting recovery endpoint: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
endpoint, err = addPortIfMissing(endpoint, constants.RecoveryPort)
|
endpoint, err = addPortIfMissing(endpoint, constants.RecoveryPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -248,6 +253,7 @@ func (r *recoverCmd) parseRecoverFlags(cmd *cobra.Command, fileHandler file.Hand
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
secretPath: masterSecretPath,
|
secretPath: masterSecretPath,
|
||||||
configPath: configPath,
|
configPath: configPath,
|
||||||
|
maaURL: idFile.AttestationURL,
|
||||||
force: force,
|
force: force,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -84,9 +83,8 @@ func (v *verifyCmd) verify(cmd *cobra.Command, fileHandler file.Handler, verifyC
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := conf.GetProvider()
|
v.log.Debugf("Creating aTLS Validator for %s", conf.AttestationVariant)
|
||||||
v.log.Debugf("Creating aTLS Validator for %s", provider)
|
validators, err := cloudcmd.NewValidator(conf, flags.maaURL, v.log)
|
||||||
validators, err := cloudcmd.NewValidator(conf, v.log)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -143,13 +141,16 @@ func (v *verifyCmd) parseVerifyFlags(cmd *cobra.Command, fileHandler file.Handle
|
||||||
}
|
}
|
||||||
v.log.Debugf("Flag 'force' set to %t", force)
|
v.log.Debugf("Flag 'force' set to %t", force)
|
||||||
|
|
||||||
|
var idFile clusterid.File
|
||||||
|
if err := fileHandler.ReadJSON(constants.ClusterIDsFileName, &idFile); err != nil && !errors.Is(err, afero.ErrFileNotFound) {
|
||||||
|
return verifyFlags{}, fmt.Errorf("reading cluster ID file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Get empty values from ID file
|
// Get empty values from ID file
|
||||||
emptyEndpoint := endpoint == ""
|
emptyEndpoint := endpoint == ""
|
||||||
emptyIDs := ownerID == "" && clusterID == ""
|
emptyIDs := ownerID == "" && clusterID == ""
|
||||||
if emptyEndpoint || emptyIDs {
|
if emptyEndpoint || emptyIDs {
|
||||||
v.log.Debugf("Trying to supplement empty flag values from %q", constants.ClusterIDsFileName)
|
v.log.Debugf("Trying to supplement empty flag values from %q", constants.ClusterIDsFileName)
|
||||||
var idFile clusterid.File
|
|
||||||
if err := fileHandler.ReadJSON(constants.ClusterIDsFileName, &idFile); err == nil {
|
|
||||||
if emptyEndpoint {
|
if emptyEndpoint {
|
||||||
cmd.Printf("Using endpoint from %q. Specify --node-endpoint to override this.\n", constants.ClusterIDsFileName)
|
cmd.Printf("Using endpoint from %q. Specify --node-endpoint to override this.\n", constants.ClusterIDsFileName)
|
||||||
endpoint = idFile.IP
|
endpoint = idFile.IP
|
||||||
|
@ -159,9 +160,6 @@ func (v *verifyCmd) parseVerifyFlags(cmd *cobra.Command, fileHandler file.Handle
|
||||||
ownerID = idFile.OwnerID
|
ownerID = idFile.OwnerID
|
||||||
clusterID = idFile.ClusterID
|
clusterID = idFile.ClusterID
|
||||||
}
|
}
|
||||||
} else if !errors.Is(err, fs.ErrNotExist) {
|
|
||||||
return verifyFlags{}, fmt.Errorf("reading cluster ID file: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
|
@ -178,6 +176,7 @@ func (v *verifyCmd) parseVerifyFlags(cmd *cobra.Command, fileHandler file.Handle
|
||||||
configPath: configPath,
|
configPath: configPath,
|
||||||
ownerID: ownerID,
|
ownerID: ownerID,
|
||||||
clusterID: clusterID,
|
clusterID: clusterID,
|
||||||
|
maaURL: idFile.AttestationURL,
|
||||||
force: force,
|
force: force,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -187,6 +186,7 @@ type verifyFlags struct {
|
||||||
ownerID string
|
ownerID string
|
||||||
clusterID string
|
clusterID string
|
||||||
configPath string
|
configPath string
|
||||||
|
maaURL string
|
||||||
force bool
|
force bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -319,6 +319,7 @@ go_library(
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/helm",
|
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/helm",
|
||||||
visibility = ["//cli:__subpackages__"],
|
visibility = ["//cli:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/compatibility",
|
"//internal/compatibility",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
|
@ -352,6 +353,7 @@ go_test(
|
||||||
data = glob(["testdata/**"]),
|
data = glob(["testdata/**"]),
|
||||||
embed = [":helm"],
|
embed = [":helm"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/cloud/cloudprovider",
|
"//internal/cloud/cloudprovider",
|
||||||
"//internal/compatibility",
|
"//internal/compatibility",
|
||||||
|
|
|
@ -7,9 +7,7 @@ data:
|
||||||
{{/* mustToJson is required so the json-strings passed from go are of type string in the rendered yaml. */}}
|
{{/* mustToJson is required so the json-strings passed from go are of type string in the rendered yaml. */}}
|
||||||
measurements: {{ .Values.measurements | mustToJson }}
|
measurements: {{ .Values.measurements | mustToJson }}
|
||||||
{{- if eq .Values.csp "Azure" }}
|
{{- if eq .Values.csp "Azure" }}
|
||||||
{{/* ConfigMap.data is of type map[string]string. quote will not quote a quoted string. */}}
|
idKeyConfig: {{ .Values.idKeyConfig | mustToJson }}
|
||||||
enforceIdKeyDigest: {{ .Values.enforceIdKeyDigest | quote }}
|
|
||||||
idkeydigests: {{ .Values.idkeydigests | mustToJson }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
binaryData:
|
binaryData:
|
||||||
measurementSalt: {{ .Values.measurementSalt }}
|
measurementSalt: {{ .Values.measurementSalt }}
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
"examples": ["{'1':{'expected':'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA','warnOnly':true},'15':{'expected':'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=','warnOnly':true}}"]
|
"examples": ["{'1':{'expected':'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA','warnOnly':true},'15':{'expected':'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=','warnOnly':true}}"]
|
||||||
},
|
},
|
||||||
"enforceIdKeyDigest": {
|
"enforceIdKeyDigest": {
|
||||||
"description": "Whether or not idkeydigest should be enforced during attestation on azure.",
|
"description": "ID Key Digest enforcement policy.",
|
||||||
"type": "boolean"
|
"enum": ["StrictChecking", "MAAFallback", "WarnOnly"]
|
||||||
},
|
},
|
||||||
"idkeydigests": {
|
"idKeyConfig": {
|
||||||
"description": "List of expected idkeydigest values for Azure SNP attestation.",
|
"description": "Configuration for validating the ID Key Digest of the SEV-SNP attestation.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"examples": ["[\"57486a447ec0f1958002a22a06b7673b9fd27d11e1c6527498056054c5fa92d23c50f9de44072760fe2b6fb89740b696\", \"0356215882a825279a85b300b0b742931d113bf7e32dde2e50ffde7ec743ca491ecdd7f336dc28a6e0b2bb57af7a44a3\"]"]
|
"examples": ["{'EnforcementPolicy': 'MAAFallback', 'MAAURL': 'https://192.0.2.1:8080/maa', 'IDKeyDigests': ['57486a447ec0f1958002a22a06b7673b9fd27d11e1c6527498056054c5fa92d23c50f9de44072760fe2b6fb89740b696', '0356215882a825279a85b300b0b742931d113bf7e32dde2e50ffde7ec743ca491ecdd7f336dc28a6e0b2bb57af7a44a3'}"]
|
||||||
},
|
},
|
||||||
"image": {
|
"image": {
|
||||||
"description": "Container image to use for the spawned pods.",
|
"description": "Container image to use for the spawned pods.",
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
"properties": { "csp": { "const": "azure" } },
|
"properties": { "csp": { "const": "azure" } },
|
||||||
"required": ["csp"]
|
"required": ["csp"]
|
||||||
},
|
},
|
||||||
"then": { "required": ["enforceIdKeyDigest", "idkeydigests"] },
|
"then": { "required": ["idKeyConfig"] },
|
||||||
"title": "Values",
|
"title": "Values",
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
csp: "gcp"
|
csp: "gcp"
|
||||||
attestationVariant: ""
|
attestationVariant: ""
|
||||||
|
measurements: ""
|
||||||
|
idKeyConfig: ""
|
||||||
|
measurementSalt: ""
|
||||||
joinServicePort: 9090
|
joinServicePort: 9090
|
||||||
joinServiceNodePort: 30090
|
joinServiceNodePort: 30090
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -107,7 +108,7 @@ func AvailableServiceVersions() (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the embedded helm charts.
|
// Load the embedded helm charts.
|
||||||
func (i *ChartLoader) Load(config *config.Config, conformanceMode bool, masterSecret, salt []byte) ([]byte, error) {
|
func (i *ChartLoader) Load(config *config.Config, conformanceMode bool, masterSecret, salt []byte, maaURL string) ([]byte, error) {
|
||||||
ciliumRelease, err := i.loadRelease(ciliumInfo)
|
ciliumRelease, err := i.loadRelease(ciliumInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("loading cilium: %w", err)
|
return nil, fmt.Errorf("loading cilium: %w", err)
|
||||||
|
@ -128,7 +129,7 @@ func (i *ChartLoader) Load(config *config.Config, conformanceMode bool, masterSe
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("loading constellation-services: %w", err)
|
return nil, fmt.Errorf("loading constellation-services: %w", err)
|
||||||
}
|
}
|
||||||
if err := extendConstellationServicesValues(conServicesRelease.Values, config, masterSecret, salt); err != nil {
|
if err := extendConstellationServicesValues(conServicesRelease.Values, config, masterSecret, salt, maaURL); err != nil {
|
||||||
return nil, fmt.Errorf("extending constellation-services values: %w", err)
|
return nil, fmt.Errorf("extending constellation-services values: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,7 +468,9 @@ func (i *ChartLoader) loadConstellationServicesValues() (map[string]any, error)
|
||||||
// reuse user input from the init step. However, we can't rely on reuse-values, because
|
// reuse user input from the init step. However, we can't rely on reuse-values, because
|
||||||
// during upgrades all values need to be set locally as they might have changed.
|
// during upgrades all values need to be set locally as they might have changed.
|
||||||
// Also, the charts are not rendered correctly without all of these values.
|
// Also, the charts are not rendered correctly without all of these values.
|
||||||
func extendConstellationServicesValues(in map[string]any, config *config.Config, masterSecret, salt []byte) error {
|
func extendConstellationServicesValues(
|
||||||
|
in map[string]any, config *config.Config, masterSecret, salt []byte, maaURL string,
|
||||||
|
) error {
|
||||||
keyServiceValues, ok := in["key-service"].(map[string]any)
|
keyServiceValues, ok := in["key-service"].(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("missing 'key-service' key")
|
return errors.New("missing 'key-service' key")
|
||||||
|
@ -494,13 +497,17 @@ func extendConstellationServicesValues(in map[string]any, config *config.Config,
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("invalid join-service values")
|
return errors.New("invalid join-service values")
|
||||||
}
|
}
|
||||||
joinServiceVals["enforceIdKeyDigest"] = config.EnforcesIDKeyDigest()
|
|
||||||
|
|
||||||
marshalledDigests, err := json.Marshal(config.IDKeyDigests())
|
idKeyCfg := idkeydigest.Config{
|
||||||
if err != nil {
|
IDKeyDigests: config.IDKeyDigests(),
|
||||||
return fmt.Errorf("marshalling id key digests: %w", err)
|
EnforcementPolicy: config.IDKeyDigestPolicy(),
|
||||||
|
MAAURL: maaURL,
|
||||||
}
|
}
|
||||||
joinServiceVals["idkeydigests"] = string(marshalledDigests)
|
marshalledCfg, err := json.Marshal(idKeyCfg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("marshalling id key digest config: %w", err)
|
||||||
|
}
|
||||||
|
joinServiceVals["idKeyConfig"] = string(marshalledCfg)
|
||||||
|
|
||||||
in["azure"] = map[string]any{
|
in["azure"] = map[string]any{
|
||||||
"deployCSIDriver": config.DeployCSIDriver(),
|
"deployCSIDriver": config.DeployCSIDriver(),
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -38,7 +39,7 @@ func TestLoad(t *testing.T) {
|
||||||
|
|
||||||
config := &config.Config{Provider: config.ProviderConfig{GCP: &config.GCPConfig{}}}
|
config := &config.Config{Provider: config.ProviderConfig{GCP: &config.GCPConfig{}}}
|
||||||
chartLoader := ChartLoader{csp: config.GetProvider()}
|
chartLoader := ChartLoader{csp: config.GetProvider()}
|
||||||
release, err := chartLoader.Load(config, true, []byte("secret"), []byte("salt"))
|
release, err := chartLoader.Load(config, true, []byte("secret"), []byte("salt"), "https://192.0.2.1:8080/maa")
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
var helmReleases helm.Releases
|
var helmReleases helm.Releases
|
||||||
|
@ -72,7 +73,11 @@ func TestConstellationServices(t *testing.T) {
|
||||||
AttestationVariant: oid.AzureSEVSNP{}.String(),
|
AttestationVariant: oid.AzureSEVSNP{}.String(),
|
||||||
Provider: config.ProviderConfig{Azure: &config.AzureConfig{
|
Provider: config.ProviderConfig{Azure: &config.AzureConfig{
|
||||||
DeployCSIDriver: toPtr(true),
|
DeployCSIDriver: toPtr(true),
|
||||||
EnforceIDKeyDigest: toPtr(true),
|
EnforceIDKeyDigest: idkeydigest.StrictChecking,
|
||||||
|
IDKeyDigest: [][]byte{
|
||||||
|
{0xba, 0xaa, 0xaa, 0xad, 0xba, 0xaa, 0xaa, 0xad, 0xba, 0xaa, 0xaa, 0xad, 0xba, 0xaa, 0xaa, 0xad, 0xba, 0xaa, 0xaa, 0xad, 0xba, 0xaa, 0xaa, 0xad, 0xba, 0xaa, 0xaa, 0xad, 0xba, 0xaa, 0xaa, 0xad},
|
||||||
|
{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
|
||||||
|
},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
enforceIDKeyDigest: true,
|
enforceIDKeyDigest: true,
|
||||||
|
@ -127,7 +132,7 @@ func TestConstellationServices(t *testing.T) {
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
values, err := chartLoader.loadConstellationServicesValues()
|
values, err := chartLoader.loadConstellationServicesValues()
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
err = extendConstellationServicesValues(values, tc.config, []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
err = extendConstellationServicesValues(values, tc.config, []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), "https://192.0.2.1:8080/maa")
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
options := chartutil.ReleaseOptions{
|
options := chartutil.ReleaseOptions{
|
||||||
|
|
|
@ -5,7 +5,6 @@ metadata:
|
||||||
namespace: testNamespace
|
namespace: testNamespace
|
||||||
data:
|
data:
|
||||||
measurements: "{\"1\":{\"expected\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"warnOnly\":false}}"
|
measurements: "{\"1\":{\"expected\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"warnOnly\":false}}"
|
||||||
enforceIdKeyDigest: "true"
|
idKeyConfig: "{\"idKeyDigests\":[\"baaaaaadbaaaaaadbaaaaaadbaaaaaadbaaaaaadbaaaaaadbaaaaaadbaaaaaad\",\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"],\"enforcementPolicy\":\"StrictChecking\",\"maaURL\":\"https://192.0.2.1:8080/maa\"}"
|
||||||
idkeydigests: "[\"baaaaaadbaaaaaadbaaaaaadbaaaaaadbaaaaaadbaaaaaadbaaaaaadbaaaaaad\", \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"]"
|
|
||||||
binaryData:
|
binaryData:
|
||||||
measurementSalt: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
measurementSalt: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -33,6 +33,7 @@ replace (
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api => ./operators/constellation-node-operator/api
|
github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api => ./operators/constellation-node-operator/api
|
||||||
|
github.com/google/go-tpm => github.com/thomasten/go-tpm v0.0.0-20230222180349-bb3cc5560299
|
||||||
github.com/google/go-tpm-tools => github.com/daniel-weisse/go-tpm-tools v0.0.0-20230105122812-f7474d459dfc
|
github.com/google/go-tpm-tools => github.com/daniel-weisse/go-tpm-tools v0.0.0-20230105122812-f7474d459dfc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ require (
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0
|
github.com/coreos/go-systemd/v22 v22.5.0
|
||||||
github.com/docker/docker v20.10.22+incompatible
|
github.com/docker/docker v20.10.22+incompatible
|
||||||
github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api v0.0.0
|
github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api v0.0.0
|
||||||
|
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f
|
||||||
github.com/fsnotify/fsnotify v1.6.0
|
github.com/fsnotify/fsnotify v1.6.0
|
||||||
github.com/go-playground/locales v0.14.1
|
github.com/go-playground/locales v0.14.1
|
||||||
github.com/go-playground/universal-translator v0.18.1
|
github.com/go-playground/universal-translator v0.18.1
|
||||||
|
@ -187,6 +189,7 @@ require (
|
||||||
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
||||||
github.com/go-errors/errors v1.4.2 // indirect
|
github.com/go-errors/errors v1.4.2 // indirect
|
||||||
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
|
||||||
github.com/go-logr/logr v1.2.3 // indirect
|
github.com/go-logr/logr v1.2.3 // indirect
|
||||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
github.com/go-openapi/analysis v0.21.4 // indirect
|
||||||
github.com/go-openapi/errors v0.20.3 // indirect
|
github.com/go-openapi/errors v0.20.3 // indirect
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -405,6 +405,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
||||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=
|
||||||
|
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f/go.mod h1:hX9gZBSvliJcBEAyrJDh7990hLRg/Is+6PBpDZWSMoc=
|
||||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||||
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
||||||
|
@ -473,6 +475,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
|
||||||
github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4=
|
github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4=
|
||||||
github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
|
github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
|
||||||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||||
|
@ -677,8 +681,6 @@ github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVgg
|
||||||
github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
|
github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
|
||||||
github.com/google/go-sev-guest v0.4.1 h1:IjxtGAvzR+zSyAqMc1FWfYKCg1cwPkBly9+Xog3YMZc=
|
github.com/google/go-sev-guest v0.4.1 h1:IjxtGAvzR+zSyAqMc1FWfYKCg1cwPkBly9+Xog3YMZc=
|
||||||
github.com/google/go-sev-guest v0.4.1/go.mod h1:UEi9uwoPbLdKGl1QHaq1G8pfCbQ4QP0swWX4J0k6r+Q=
|
github.com/google/go-sev-guest v0.4.1/go.mod h1:UEi9uwoPbLdKGl1QHaq1G8pfCbQ4QP0swWX4J0k6r+Q=
|
||||||
github.com/google/go-tpm v0.3.3 h1:P/ZFNBZYXRxc+z7i5uyd8VP7MaDteuLZInzrH2idRGo=
|
|
||||||
github.com/google/go-tpm v0.3.3/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51BeghL4=
|
|
||||||
github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
||||||
github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus=
|
github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus=
|
||||||
github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
||||||
|
@ -1319,6 +1321,8 @@ github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 h1:iGnD/q91
|
||||||
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613/go.mod h1:g6AnIpDSYMcphz193otpSIzN+11Rs+AAIIC6rm1enug=
|
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613/go.mod h1:g6AnIpDSYMcphz193otpSIzN+11Rs+AAIIC6rm1enug=
|
||||||
github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA=
|
github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA=
|
||||||
github.com/theupdateframework/go-tuf v0.5.2/go.mod h1:SyMV5kg5n4uEclsyxXJZI2UxPFJNDc4Y+r7wv+MlvTA=
|
github.com/theupdateframework/go-tuf v0.5.2/go.mod h1:SyMV5kg5n4uEclsyxXJZI2UxPFJNDc4Y+r7wv+MlvTA=
|
||||||
|
github.com/thomasten/go-tpm v0.0.0-20230222180349-bb3cc5560299 h1:4/WcA7Q05f5to+jVERKcZjU5NJ89DiRHP3UUZHLfAtw=
|
||||||
|
github.com/thomasten/go-tpm v0.0.0-20230222180349-bb3cc5560299/go.mod h1:9Hyn3rgnzWF9XBWVk6ml6A6hNkbWjNFlDQL51BeghL4=
|
||||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
|
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
|
||||||
|
@ -1483,6 +1487,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
|
|
@ -50,10 +50,14 @@ require (
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute v1.18.0 // indirect
|
cloud.google.com/go/compute v1.18.0 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||||
|
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect
|
||||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
|
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v1.0.0 // indirect
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.1.0 // indirect
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.1.0 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||||
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
|
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
|
||||||
|
@ -114,6 +118,7 @@ require (
|
||||||
github.com/docker/go-metrics v0.0.1 // indirect
|
github.com/docker/go-metrics v0.0.1 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api v0.0.0 // indirect
|
github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api v0.0.0 // indirect
|
||||||
|
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||||
|
@ -124,6 +129,7 @@ require (
|
||||||
github.com/go-git/gcfg v1.5.0 // indirect
|
github.com/go-git/gcfg v1.5.0 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
||||||
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
|
||||||
github.com/go-logr/logr v1.2.3 // indirect
|
github.com/go-logr/logr v1.2.3 // indirect
|
||||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
github.com/go-openapi/analysis v0.21.4 // indirect
|
||||||
github.com/go-openapi/errors v0.20.3 // indirect
|
github.com/go-openapi/errors v0.20.3 // indirect
|
||||||
|
@ -139,6 +145,7 @@ require (
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
|
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
@ -197,6 +204,7 @@ require (
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
|
github.com/microsoft/ApplicationInsights-Go v0.4.4 // indirect
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
|
25
hack/go.sum
25
hack/go.sum
|
@ -63,6 +63,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||||
cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g=
|
cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g=
|
||||||
|
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c h1:5eeuG0BHx1+DHeT3AP+ISKZ2ht1UjGhm581ljqYpVeQ=
|
||||||
|
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=
|
||||||
code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
|
code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
|
||||||
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
|
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
|
||||||
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
|
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
|
||||||
|
@ -85,6 +87,16 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 h1:T8quHYlUGyb/oqtSTwqlC
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1/go.mod h1:gLa1CL2RNE4s7M3yopJ/p0iq5DdY6Yv5ZUt9MTRZOQM=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1/go.mod h1:gLa1CL2RNE4s7M3yopJ/p0iq5DdY6Yv5ZUt9MTRZOQM=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 h1:+5VZ72z0Qan5Bog5C+ZkgSqUbeVUd9wgtHOrIKuc5b8=
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 h1:+5VZ72z0Qan5Bog5C+ZkgSqUbeVUd9wgtHOrIKuc5b8=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v1.0.0 h1:BpGGvzarSyE7kQF1x1hptUcGmNzZEE3yYI+uqBSNRxk=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v1.0.0/go.mod h1:1ijUM40peD7YK5MFEJja2wjjp4eimFNWv0NXoY3nsZM=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v3 v3.0.1 h1:H3g2mkmu105ON0c/Gqx3Bm+bzoIijLom8LmV9Gjn7X0=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.1.0 h1:Vjq3Uy3JAU1DTxbA+uX6BegIhgO2pyFltbfbmDa9KdI=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.1.0/go.mod h1:Q3u+T/qw3Kb1Wf3DFKiFwEZlyaAyPb4yBgWm9wq7yh8=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0 h1:lMW1lD/17LUA5z1XTURo7LcVG2ICBPlyMHjIUrcFZNQ=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.1.0 h1:mk57wRUA8fyjFxVcPPGv4shLcWDXPFYokTJL9zJxQtE=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.1.0/go.mod h1:mU96hbp8qJDA9OzTV1Ji7wCyPyaqC5kI6ZPsZfJ8sE4=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8=
|
||||||
github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0=
|
github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0=
|
||||||
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
|
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||||
|
@ -102,6 +114,7 @@ github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSY
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
|
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
|
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
|
||||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=
|
github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=
|
||||||
github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
|
github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
|
||||||
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
|
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
|
||||||
|
@ -361,6 +374,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
||||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f h1:J9k1gV8YA5beC6jANKQy5O7UtaKS3ueuanxUan5Y5NU=
|
||||||
|
github.com/edgelesssys/go-azguestattestation v0.0.0-20230303085714-62ede861d33f/go.mod h1:hX9gZBSvliJcBEAyrJDh7990hLRg/Is+6PBpDZWSMoc=
|
||||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||||
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
||||||
|
@ -436,6 +451,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
|
||||||
github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4=
|
github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4=
|
||||||
github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
|
github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
|
||||||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||||
|
@ -541,6 +558,9 @@ github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZ
|
||||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
|
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
|
||||||
|
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||||
|
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
@ -961,6 +981,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
|
github.com/microsoft/ApplicationInsights-Go v0.4.4 h1:G4+H9WNs6ygSCe6sUyxRc2U81TI5Es90b2t/MwX5KqY=
|
||||||
|
github.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||||
|
@ -1037,6 +1059,7 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
|
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
|
||||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc=
|
github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc=
|
||||||
|
@ -1270,6 +1293,7 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
||||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
|
github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0=
|
||||||
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 h1:iGnD/q9160NWqKZZ5vY4p0dMiYMRknzctfSkqA4nBDw=
|
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 h1:iGnD/q9160NWqKZZ5vY4p0dMiYMRknzctfSkqA4nBDw=
|
||||||
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613/go.mod h1:g6AnIpDSYMcphz193otpSIzN+11Rs+AAIIC6rm1enug=
|
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613/go.mod h1:g6AnIpDSYMcphz193otpSIzN+11Rs+AAIIC6rm1enug=
|
||||||
github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA=
|
github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA=
|
||||||
|
@ -1440,6 +1464,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
|
|
@ -43,6 +43,7 @@ go_test(
|
||||||
"@com_github_aws_aws_sdk_go_v2_service_ec2//types",
|
"@com_github_aws_aws_sdk_go_v2_service_ec2//types",
|
||||||
"@com_github_aws_smithy_go//middleware",
|
"@com_github_aws_smithy_go//middleware",
|
||||||
"@com_github_google_go_tpm_tools//client",
|
"@com_github_google_go_tpm_tools//client",
|
||||||
|
"@com_github_google_go_tpm_tools//proto/attest",
|
||||||
"@com_github_stretchr_testify//assert",
|
"@com_github_stretchr_testify//assert",
|
||||||
"@com_github_stretchr_testify//require",
|
"@com_github_stretchr_testify//require",
|
||||||
],
|
],
|
||||||
|
|
|
@ -52,8 +52,8 @@ func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
||||||
|
|
||||||
// getInstanceInfo returns information about the current instance using the aws Metadata SDK.
|
// getInstanceInfo returns information about the current instance using the aws Metadata SDK.
|
||||||
// The returned bytes will be written into the attestation document.
|
// The returned bytes will be written into the attestation document.
|
||||||
func getInstanceInfo(client awsMetaData) func(tpm io.ReadWriteCloser) ([]byte, error) {
|
func getInstanceInfo(client awsMetaData) func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) {
|
||||||
return func(io.ReadWriteCloser) ([]byte, error) {
|
return func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) {
|
||||||
ec2InstanceIdentityOutput, err := client.GetInstanceIdentityDocument(context.Background(), &imds.GetInstanceIdentityDocumentInput{})
|
ec2InstanceIdentityOutput, err := client.GetInstanceIdentityDocument(context.Background(), &imds.GetInstanceIdentityDocumentInput{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("unable to fetch instance identity document")
|
return nil, errors.New("unable to fetch instance identity document")
|
||||||
|
|
|
@ -91,7 +91,7 @@ func TestGetInstanceInfo(t *testing.T) {
|
||||||
instanceInfoFunc := getInstanceInfo(&tc.client)
|
instanceInfoFunc := getInstanceInfo(&tc.client)
|
||||||
assert.NotNil(instanceInfoFunc)
|
assert.NotNil(instanceInfoFunc)
|
||||||
|
|
||||||
info, err := instanceInfoFunc(tpm)
|
info, err := instanceInfoFunc(context.Background(), tpm, nil)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
assert.Nil(info)
|
assert.Nil(info)
|
||||||
|
|
|
@ -44,9 +44,9 @@ func NewValidator(pcrs measurements.M, log vtpm.AttestationLogger) *Validator {
|
||||||
|
|
||||||
// getTrustedKeys return the public area of the provides attestation key.
|
// getTrustedKeys return the public area of the provides attestation key.
|
||||||
// Normally, here the trust of this key should be verified, but currently AWS does not provide this feature.
|
// Normally, here the trust of this key should be verified, but currently AWS does not provide this feature.
|
||||||
func getTrustedKey(akPub []byte, _ []byte) (crypto.PublicKey, error) {
|
func getTrustedKey(_ context.Context, attDoc vtpm.AttestationDocument, _ []byte) (crypto.PublicKey, error) {
|
||||||
// Copied from https://github.com/edgelesssys/constellation/blob/main/internal/attestation/qemu/validator.go
|
// Copied from https://github.com/edgelesssys/constellation/blob/main/internal/attestation/qemu/validator.go
|
||||||
pubArea, err := tpm2.DecodePublic(akPub)
|
pubArea, err := tpm2.DecodePublic(attDoc.Attestation.AkPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,23 +16,24 @@ import (
|
||||||
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
|
"github.com/google/go-tpm-tools/proto/attest"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGeTrustedKey(t *testing.T) {
|
func TestGeTrustedKey(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
attDoc []byte
|
akPub []byte
|
||||||
nonce []byte
|
info []byte
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"nul byte docs": {
|
"nul byte docs": {
|
||||||
attDoc: []byte{0x00, 0x00, 0x00, 0x00},
|
akPub: []byte{0x00, 0x00, 0x00, 0x00},
|
||||||
nonce: []byte{0x00, 0x00, 0x00, 0x00},
|
info: []byte{0x00, 0x00, 0x00, 0x00},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"nil": {
|
"nil": {
|
||||||
attDoc: nil,
|
akPub: nil,
|
||||||
nonce: nil,
|
info: nil,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,16 @@ func TestGeTrustedKey(t *testing.T) {
|
||||||
for name, tc := range testCases {
|
for name, tc := range testCases {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
out, err := getTrustedKey(tc.attDoc, tc.nonce)
|
out, err := getTrustedKey(
|
||||||
|
context.Background(),
|
||||||
|
vtpm.AttestationDocument{
|
||||||
|
Attestation: &attest.Attestation{
|
||||||
|
AkPub: tc.akPub,
|
||||||
|
},
|
||||||
|
InstanceInfo: tc.info,
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
|
|
@ -7,6 +7,7 @@ go_library(
|
||||||
"errors.go",
|
"errors.go",
|
||||||
"imds.go",
|
"imds.go",
|
||||||
"issuer.go",
|
"issuer.go",
|
||||||
|
"maa.go",
|
||||||
"snp.go",
|
"snp.go",
|
||||||
"validator.go",
|
"validator.go",
|
||||||
],
|
],
|
||||||
|
@ -16,8 +17,10 @@ go_library(
|
||||||
"//internal/attestation/idkeydigest",
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
|
"//internal/cloud/azure",
|
||||||
"//internal/crypto",
|
"//internal/crypto",
|
||||||
"//internal/oid",
|
"//internal/oid",
|
||||||
|
"@com_github_edgelesssys_go_azguestattestation//maa",
|
||||||
"@com_github_google_go_tpm//tpm2",
|
"@com_github_google_go_tpm//tpm2",
|
||||||
"@com_github_google_go_tpm_tools//client",
|
"@com_github_google_go_tpm_tools//client",
|
||||||
"@com_github_google_go_tpm_tools//proto/attest",
|
"@com_github_google_go_tpm_tools//proto/attest",
|
||||||
|
@ -41,8 +44,11 @@ go_test(
|
||||||
"//internal/attestation/idkeydigest",
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/attestation/simulator",
|
"//internal/attestation/simulator",
|
||||||
"//internal/attestation/vtpm",
|
"//internal/attestation/vtpm",
|
||||||
|
"//internal/logger",
|
||||||
|
"@com_github_edgelesssys_go_azguestattestation//maa",
|
||||||
"@com_github_google_go_tpm//tpm2",
|
"@com_github_google_go_tpm//tpm2",
|
||||||
"@com_github_google_go_tpm_tools//client",
|
"@com_github_google_go_tpm_tools//client",
|
||||||
|
"@com_github_google_go_tpm_tools//proto/attest",
|
||||||
"@com_github_stretchr_testify//assert",
|
"@com_github_stretchr_testify//assert",
|
||||||
"@com_github_stretchr_testify//require",
|
"@com_github_stretchr_testify//require",
|
||||||
],
|
],
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (e *idKeyError) Unwrap() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *idKeyError) Error() string {
|
func (e *idKeyError) Error() string {
|
||||||
return fmt.Sprintf("configured idkeydigests %x doesn't contain reported idkeydigest %x", e.expectedValues, e.encounteredValue)
|
return fmt.Sprintf("configured idkeydigests %x don't contain reported idkeydigest %x", e.expectedValues, e.encounteredValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
type versionError struct {
|
type versionError struct {
|
||||||
|
|
|
@ -8,42 +8,28 @@ package snp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/cloud/azure"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Modified version of bootstrapper/cloudprovider/azure/imds.go
|
const tagMAAURL = "constellation-maa-url"
|
||||||
|
|
||||||
const (
|
|
||||||
imdsVcekURL = "http://169.254.169.254/metadata/THIM/amd/certification"
|
|
||||||
)
|
|
||||||
|
|
||||||
type imdsClient struct {
|
type imdsClient struct {
|
||||||
client *http.Client
|
imdsClient *azure.IMDSClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve retrieves instance metadata from the azure imds API.
|
func newIMDSClient() *imdsClient {
|
||||||
func (c imdsClient) getVcek(ctx context.Context) (vcekResponse, error) {
|
return &imdsClient{
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, imdsVcekURL, http.NoBody)
|
imdsClient: azure.NewIMDSClient(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *imdsClient) getMAAURL(ctx context.Context) (string, error) {
|
||||||
|
tags, err := c.imdsClient.Tags(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vcekResponse{}, err
|
return "", fmt.Errorf("getting tags: %w", err)
|
||||||
}
|
|
||||||
req.Header.Add("Metadata", "True")
|
|
||||||
resp, err := c.client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return vcekResponse{}, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
var res vcekResponse
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
||||||
return vcekResponse{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return tags[tagMAAURL], nil
|
||||||
}
|
|
||||||
|
|
||||||
type vcekResponse struct {
|
|
||||||
VcekCert string
|
|
||||||
CertificateChain string
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,98 +7,69 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
package snp
|
package snp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/oid"
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
|
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||||
tpmclient "github.com/google/go-tpm-tools/client"
|
tpmclient "github.com/google/go-tpm-tools/client"
|
||||||
"github.com/google/go-tpm/tpm2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const tpmAkIdx = 0x81000003
|
||||||
lenHclHeader = 0x20
|
|
||||||
lenSnpReport = 0x4a0
|
|
||||||
lenSnpReportRuntimeDataPadding = 0x14
|
|
||||||
tpmReportIdx = 0x01400001
|
|
||||||
tpmAkIdx = 0x81000003
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetIDKeyDigest reads the idkeydigest from the snp report saved in the TPM's non-volatile memory.
|
|
||||||
func GetIDKeyDigest(open vtpm.TPMOpenFunc) ([]byte, error) {
|
|
||||||
tpm, err := open()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer tpm.Close()
|
|
||||||
|
|
||||||
reportRaw, err := tpm2.NVReadEx(tpm, tpmReportIdx, tpm2.HandleOwner, "", 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("reading idx %x from TPM: %w", tpmReportIdx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
report, err := newSNPReportFromBytes(reportRaw[lenHclHeader:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("creating snp report: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return report.IDKeyDigest[:], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issuer for Azure TPM attestation.
|
// Issuer for Azure TPM attestation.
|
||||||
type Issuer struct {
|
type Issuer struct {
|
||||||
oid.AzureSEVSNP
|
oid.AzureSEVSNP
|
||||||
*vtpm.Issuer
|
*vtpm.Issuer
|
||||||
|
|
||||||
|
imds imdsAPI
|
||||||
|
maa maaTokenCreator
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIssuer initializes a new Azure Issuer.
|
// NewIssuer initializes a new Azure Issuer.
|
||||||
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
||||||
imdsAPI := imdsClient{
|
i := &Issuer{
|
||||||
client: &http.Client{Transport: &http.Transport{Proxy: nil}},
|
imds: newIMDSClient(),
|
||||||
|
maa: newMAAClient(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Issuer{
|
i.Issuer = vtpm.NewIssuer(
|
||||||
Issuer: vtpm.NewIssuer(
|
|
||||||
vtpm.OpenVTPM,
|
vtpm.OpenVTPM,
|
||||||
getAttestationKey,
|
getAttestationKey,
|
||||||
getInstanceInfo(&tpmReport{}, imdsAPI),
|
i.getInstanceInfo,
|
||||||
log,
|
log,
|
||||||
),
|
)
|
||||||
}
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
// getInstanceInfo loads and returns the SEV-SNP attestation report [1] and the
|
func (i *Issuer) getInstanceInfo(ctx context.Context, tpm io.ReadWriteCloser, userData []byte) ([]byte, error) {
|
||||||
// AMD VCEK certificate chain.
|
params, err := i.maa.newParameters(ctx, userData, tpm)
|
||||||
// The attestation report is loaded from the TPM, the certificate chain is queried
|
|
||||||
// from the cloud metadata API.
|
|
||||||
// [1] https://github.com/AMDESE/sev-guest/blob/main/include/attestation.h
|
|
||||||
func getInstanceInfo(reportGetter tpmReportGetter, imdsapi imdsAPI) func(tpm io.ReadWriteCloser) ([]byte, error) {
|
|
||||||
return func(tpm io.ReadWriteCloser) ([]byte, error) {
|
|
||||||
hclReport, err := reportGetter.get(tpm)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("reading report from TPM: %w", err)
|
return nil, fmt.Errorf("getting system parameters: %w", err)
|
||||||
}
|
}
|
||||||
if len(hclReport) < lenHclHeader+lenSnpReport+lenSnpReportRuntimeDataPadding {
|
|
||||||
return nil, fmt.Errorf("report read from TPM is shorter then expected: %x", hclReport)
|
|
||||||
}
|
|
||||||
hclReport = hclReport[lenHclHeader:]
|
|
||||||
|
|
||||||
runtimeData, _, _ := bytes.Cut(hclReport[lenSnpReport+lenSnpReportRuntimeDataPadding:], []byte{0})
|
var maaToken string
|
||||||
|
|
||||||
vcekResponse, err := imdsapi.getVcek(context.TODO())
|
maaURL, err := i.imds.getMAAURL(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("getVcekFromIMDS: %w", err)
|
return nil, fmt.Errorf("retrieving MAA URL from IMDS API: %w", err)
|
||||||
|
}
|
||||||
|
if maaURL != "" {
|
||||||
|
maaToken, err = i.maa.createToken(ctx, tpm, maaURL, userData, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("creating MAA token: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceInfo := azureInstanceInfo{
|
instanceInfo := azureInstanceInfo{
|
||||||
Vcek: []byte(vcekResponse.VcekCert),
|
Vcek: params.VcekCert,
|
||||||
CertChain: []byte(vcekResponse.CertificateChain),
|
CertChain: params.VcekChain,
|
||||||
AttestationReport: hclReport[:0x4a0],
|
AttestationReport: params.SNPReport,
|
||||||
RuntimeData: runtimeData,
|
RuntimeData: params.RuntimeData,
|
||||||
|
MAAToken: maaToken,
|
||||||
}
|
}
|
||||||
statement, err := json.Marshal(instanceInfo)
|
statement, err := json.Marshal(instanceInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -107,7 +78,6 @@ func getInstanceInfo(reportGetter tpmReportGetter, imdsapi imdsAPI) func(tpm io.
|
||||||
|
|
||||||
return statement, nil
|
return statement, nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// getAttestationKey reads the attestation key put into the TPM during early boot.
|
// getAttestationKey reads the attestation key put into the TPM during early boot.
|
||||||
func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
||||||
|
@ -119,16 +89,11 @@ func getAttestationKey(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
||||||
return ak, nil
|
return ak, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type tpmReport struct{}
|
|
||||||
|
|
||||||
func (s *tpmReport) get(tpm io.ReadWriteCloser) ([]byte, error) {
|
|
||||||
return tpm2.NVReadEx(tpm, tpmReportIdx, tpm2.HandleOwner, "", 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
type tpmReportGetter interface {
|
|
||||||
get(tpm io.ReadWriteCloser) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type imdsAPI interface {
|
type imdsAPI interface {
|
||||||
getVcek(ctx context.Context) (vcekResponse, error)
|
getMAAURL(ctx context.Context) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type maaTokenCreator interface {
|
||||||
|
newParameters(context.Context, []byte, io.ReadWriter) (maa.Parameters, error)
|
||||||
|
createToken(context.Context, io.ReadWriter, string, []byte, maa.Parameters) (string, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,13 @@ package snp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||||
|
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||||
tpmclient "github.com/google/go-tpm-tools/client"
|
tpmclient "github.com/google/go-tpm-tools/client"
|
||||||
"github.com/google/go-tpm/tpm2"
|
"github.com/google/go-tpm/tpm2"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -23,25 +23,32 @@ import (
|
||||||
|
|
||||||
func TestGetSNPAttestation(t *testing.T) {
|
func TestGetSNPAttestation(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
report string
|
maaURL string
|
||||||
vcek string
|
maaToken string
|
||||||
certChain string
|
|
||||||
apiError error
|
apiError error
|
||||||
|
tokenErr error
|
||||||
|
paramsErr error
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"success": {
|
"success without maa": {
|
||||||
report: "48434c41010000001c070000020000000000000000000000000000000000000002000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065d0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bcb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c020000010000000200000001000000480200007b226b657973223a5b7b226b6964223a2248434c416b507562222c226b65795f6f7073223a5b22656e6372797074225d2c226b7479223a22525341222c2265223a2241514142222c226e223a22747946717641414166324746656c6b5737566352684a6e4132597659364c6a427a65554e3276614d5a6e5a74685f74466e574d6b4b35415874757379434e656c337569703356475a7a54617a3558327447566a4772732d4d56486361703951647771555856573367394f515f74456269786378372d78626c554a516b474551666e626253646e5049326c764c7a4f73315a5f30766a65444178765351726d616773366e592d634a4157482d706744564a79487470735553735f5142576b6c617a44736f3557486d6e4d743973394d75696c57586f7830525379586e55656151796859316a753752545363526e5658754e7936377a5f454a6e774d393264727746623841556430534a5f396f687645596c34615a52444543476f3056726a635348552d4a474a6575574335566844425235454f6f4356424267716539653833765f6c4a784933574c65326f7653495a49497a416d625351227d5d2c22766d2d636f6e66696775726174696f6e223a7b22636f6e736f6c652d656e61626c6564223a747275652c2263757272656e742d74696d65223a313636313435353339312c227365637572652d626f6f74223a66616c73652c2274706d2d656e61626c6564223a747275652c22766d556e697175654964223a2242364339384333422d344543372d344441362d424432462d374439384432304437423735227d7d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
vcek: "someVCEKCert",
|
|
||||||
certChain: "ASKARK",
|
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
"report too short": {
|
"success with maa": {
|
||||||
report: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
maaURL: "maaurl",
|
||||||
|
maaToken: "maatoken",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
"api fails": {
|
||||||
|
apiError: errors.New(""),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"vcek api fails": {
|
"createToken fails": {
|
||||||
report: "48434c41010000001c070000020000000000000000000000000000000000000002000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065d0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bcb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c020000010000000200000001000000480200007b226b657973223a5b7b226b6964223a2248434c416b507562222c226b65795f6f7073223a5b22656e6372797074225d2c226b7479223a22525341222c2265223a2241514142222c226e223a22747946717641414166324746656c6b5737566352684a6e4132597659364c6a427a65554e3276614d5a6e5a74685f74466e574d6b4b35415874757379434e656c337569703356475a7a54617a3558327447566a4772732d4d56486361703951647771555856573367394f515f74456269786378372d78626c554a516b474551666e626253646e5049326c764c7a4f73315a5f30766a65444178765351726d616773366e592d634a4157482d706744564a79487470735553735f5142576b6c617a44736f3557486d6e4d743973394d75696c57586f7830525379586e55656151796859316a753752545363526e5658754e7936377a5f454a6e774d393264727746623841556430534a5f396f687645596c34615a52444543476f3056726a635348552d4a474a6575574335566844425235454f6f4356424267716539653833765f6c4a784933574c65326f7653495a49497a416d625351227d5d2c22766d2d636f6e66696775726174696f6e223a7b22636f6e736f6c652d656e61626c6564223a747275652c2263757272656e742d74696d65223a313636313435353339312c227365637572652d626f6f74223a66616c73652c2274706d2d656e61626c6564223a747275652c22766d556e697175654964223a2242364339384333422d344543372d344441362d424432462d374439384432304437423735227d7d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
maaURL: "maaurl",
|
||||||
apiError: errors.New(""),
|
tokenErr: errors.New(""),
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
"newParameters fails": {
|
||||||
|
paramsErr: errors.New(""),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -51,40 +58,55 @@ func TestGetSNPAttestation(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
tpm, err := simulator.OpenSimulatedTPM()
|
|
||||||
require.NoError(err)
|
|
||||||
defer tpm.Close()
|
|
||||||
|
|
||||||
imdsClient := stubImdsClient{
|
imdsClient := stubImdsClient{
|
||||||
vcek: tc.vcek,
|
maaURL: tc.maaURL,
|
||||||
certChain: tc.certChain,
|
|
||||||
apiError: tc.apiError,
|
apiError: tc.apiError,
|
||||||
}
|
}
|
||||||
reportDecoded, err := hex.DecodeString(tc.report)
|
|
||||||
assert.NoError(err)
|
params := maa.Parameters{
|
||||||
snpAttestationReport := stubTpmReport{
|
SNPReport: []byte("snpreport"),
|
||||||
tpmContent: reportDecoded,
|
RuntimeData: []byte("runtimedata"),
|
||||||
err: nil,
|
VcekCert: []byte("vcekcert"),
|
||||||
|
VcekChain: []byte("vcekchain"),
|
||||||
}
|
}
|
||||||
|
|
||||||
attestationJSON, err := getInstanceInfo(&snpAttestationReport, imdsClient)(tpm)
|
maa := &stubMaaTokenCreator{
|
||||||
|
token: tc.maaToken,
|
||||||
|
tokenErr: tc.tokenErr,
|
||||||
|
params: params,
|
||||||
|
paramsErr: tc.paramsErr,
|
||||||
|
}
|
||||||
|
|
||||||
|
issuer := Issuer{
|
||||||
|
imds: imdsClient,
|
||||||
|
maa: maa,
|
||||||
|
}
|
||||||
|
|
||||||
|
data := []byte("data")
|
||||||
|
|
||||||
|
attestationJSON, err := issuer.getInstanceInfo(context.Background(), nil, data)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
|
assert.Equal(data, maa.gotParamsData)
|
||||||
|
if tc.maaURL == "" {
|
||||||
|
assert.Empty(maa.gotTokenData)
|
||||||
|
} else {
|
||||||
|
assert.Equal(data, maa.gotTokenData)
|
||||||
|
}
|
||||||
|
|
||||||
var instanceInfo azureInstanceInfo
|
var instanceInfo azureInstanceInfo
|
||||||
err = json.Unmarshal(attestationJSON, &instanceInfo)
|
err = json.Unmarshal(attestationJSON, &instanceInfo)
|
||||||
assert.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
if tc.wantErr {
|
assert.Equal(params.VcekCert, instanceInfo.Vcek)
|
||||||
assert.NotEqualValues(tc.report[0x20:], instanceInfo.AttestationReport)
|
assert.Equal(params.VcekChain, instanceInfo.CertChain)
|
||||||
} else {
|
assert.Equal(params.SNPReport, instanceInfo.AttestationReport)
|
||||||
assert.EqualValues(reportDecoded[0x20:0x4a0+0x20], instanceInfo.AttestationReport)
|
assert.Equal(params.RuntimeData, instanceInfo.RuntimeData)
|
||||||
assert.Equal(tc.vcek, string(instanceInfo.Vcek))
|
assert.Equal(tc.maaToken, instanceInfo.MAAToken)
|
||||||
assert.Equal(tc.certChain, string(instanceInfo.CertChain))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,30 +148,30 @@ func TestGetHCLAttestationKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type stubImdsClient struct {
|
type stubImdsClient struct {
|
||||||
vcek string
|
maaURL string
|
||||||
certChain string
|
|
||||||
apiError error
|
apiError error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c stubImdsClient) getVcek(_ context.Context) (vcekResponse, error) {
|
func (c stubImdsClient) getMAAURL(_ context.Context) (string, error) {
|
||||||
if c.apiError != nil {
|
return c.maaURL, c.apiError
|
||||||
return vcekResponse{}, c.apiError
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vcekResponse{
|
type stubMaaTokenCreator struct {
|
||||||
VcekCert: c.vcek,
|
token string
|
||||||
CertificateChain: c.certChain,
|
tokenErr error
|
||||||
}, nil
|
gotTokenData []byte
|
||||||
|
|
||||||
|
params maa.Parameters
|
||||||
|
paramsErr error
|
||||||
|
gotParamsData []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type stubTpmReport struct {
|
func (s *stubMaaTokenCreator) newParameters(_ context.Context, data []byte, _ io.ReadWriter) (maa.Parameters, error) {
|
||||||
tpmContent []byte
|
s.gotParamsData = data
|
||||||
err error
|
return s.params, s.paramsErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubTpmReport) get(_ io.ReadWriteCloser) ([]byte, error) {
|
func (s *stubMaaTokenCreator) createToken(_ context.Context, _ io.ReadWriter, _ string, data []byte, _ maa.Parameters) (string, error) {
|
||||||
if s.err != nil {
|
s.gotTokenData = data
|
||||||
return nil, s.err
|
return s.token, s.tokenErr
|
||||||
}
|
|
||||||
return s.tpmContent, nil
|
|
||||||
}
|
}
|
||||||
|
|
80
internal/attestation/azure/snp/maa.go
Normal file
80
internal/attestation/azure/snp/maa.go
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package snp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||||
|
)
|
||||||
|
|
||||||
|
type maaClient struct {
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMAAClient() *maaClient {
|
||||||
|
return &maaClient{
|
||||||
|
client: &http.Client{Transport: &http.Transport{Proxy: nil}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *maaClient) newParameters(ctx context.Context, nonce []byte, tpmHandle io.ReadWriter) (maa.Parameters, error) {
|
||||||
|
return maa.NewParameters(ctx, nonce, m.client, tpmHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *maaClient) createToken(
|
||||||
|
ctx context.Context, tpm io.ReadWriter, maaURL string, data []byte, params maa.Parameters,
|
||||||
|
) (string, error) {
|
||||||
|
tokenEnc, err := maa.GetEncryptedToken(ctx, params, data, maaURL, m.client)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("getting encrypted token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := maa.DecryptToken(tokenEnc, tpm)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("decrypting token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *maaClient) validateToken(ctx context.Context, maaURL, token string, extraData []byte) error {
|
||||||
|
keySet, err := maa.GetKeySet(ctx, maaURL, m.client)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting key set from MAA: %w", err)
|
||||||
|
}
|
||||||
|
claims, err := maa.ValidateToken(token, keySet)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("validating token: %w", err)
|
||||||
|
}
|
||||||
|
return m.validateClaims(claims, extraData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *maaClient) validateClaims(claims map[string]interface{}, extraData []byte) error {
|
||||||
|
runtime, ok := claims["x-ms-runtime"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid claims: missing x-ms-runtime")
|
||||||
|
}
|
||||||
|
payload, ok := runtime["client-payload"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid claims: missing client-payload")
|
||||||
|
}
|
||||||
|
nonce, ok := payload["nonce"].(string)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid claims: missing nonce")
|
||||||
|
}
|
||||||
|
|
||||||
|
if nonce != base64.StdEncoding.EncodeToString(extraData) {
|
||||||
|
return errors.New("invalid claims: nonce does not match extra data")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ package snp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
@ -41,18 +42,36 @@ const (
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
oid.AzureSEVSNP
|
oid.AzureSEVSNP
|
||||||
*vtpm.Validator
|
*vtpm.Validator
|
||||||
|
hclValidator hclAkValidator
|
||||||
|
maa maaValidator
|
||||||
|
|
||||||
|
idKeyDigests idkeydigest.IDKeyDigests
|
||||||
|
enforceIDKeyDigest idkeydigest.EnforceIDKeyDigest
|
||||||
|
maaURL string
|
||||||
|
|
||||||
|
log vtpm.AttestationLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator initializes a new Azure validator with the provided PCR values.
|
// NewValidator initializes a new Azure validator with the provided PCR values.
|
||||||
func NewValidator(pcrs measurements.M, idKeyDigests idkeydigest.IDKeyDigests, enforceIDKeyDigest bool, log vtpm.AttestationLogger) *Validator {
|
func NewValidator(pcrs measurements.M, idKeyConf idkeydigest.Config, log vtpm.AttestationLogger) *Validator {
|
||||||
return &Validator{
|
if log == nil {
|
||||||
Validator: vtpm.NewValidator(
|
log = nopAttestationLogger{}
|
||||||
|
}
|
||||||
|
v := &Validator{
|
||||||
|
hclValidator: &azureInstanceInfo{},
|
||||||
|
maa: newMAAClient(),
|
||||||
|
idKeyDigests: idKeyConf.IDKeyDigests,
|
||||||
|
enforceIDKeyDigest: idKeyConf.EnforcementPolicy,
|
||||||
|
maaURL: idKeyConf.MAAURL,
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
v.Validator = vtpm.NewValidator(
|
||||||
pcrs,
|
pcrs,
|
||||||
getTrustedKey(&azureInstanceInfo{}, idKeyDigests, enforceIDKeyDigest, log),
|
v.getTrustedKey,
|
||||||
validateCVM,
|
validateCVM,
|
||||||
log,
|
log,
|
||||||
),
|
)
|
||||||
}
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateCVM is a stub, since SEV-SNP attestation is already verified in trustedKeyFromSNP().
|
// validateCVM is a stub, since SEV-SNP attestation is already verified in trustedKeyFromSNP().
|
||||||
|
@ -77,12 +96,9 @@ func reverseEndian(b []byte) {
|
||||||
|
|
||||||
// getTrustedKey establishes trust in the given public key.
|
// getTrustedKey establishes trust in the given public key.
|
||||||
// It does so by verifying the SNP attestation statement in instanceInfo.
|
// It does so by verifying the SNP attestation statement in instanceInfo.
|
||||||
func getTrustedKey(
|
func (v *Validator) getTrustedKey(ctx context.Context, attDoc vtpm.AttestationDocument, extraData []byte) (crypto.PublicKey, error) {
|
||||||
hclAk HCLAkValidator, idKeyDigest idkeydigest.IDKeyDigests, enforceIDKeyDigest bool, log vtpm.AttestationLogger,
|
|
||||||
) func(akPub, instanceInfoRaw []byte) (crypto.PublicKey, error) {
|
|
||||||
return func(akPub, instanceInfoRaw []byte) (crypto.PublicKey, error) {
|
|
||||||
var instanceInfo azureInstanceInfo
|
var instanceInfo azureInstanceInfo
|
||||||
if err := json.Unmarshal(instanceInfoRaw, &instanceInfo); err != nil {
|
if err := json.Unmarshal(attDoc.InstanceInfo, &instanceInfo); err != nil {
|
||||||
return nil, fmt.Errorf("unmarshalling instanceInfoRaw: %w", err)
|
return nil, fmt.Errorf("unmarshalling instanceInfoRaw: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,22 +112,21 @@ func getTrustedKey(
|
||||||
return nil, fmt.Errorf("validating VCEK: %w", err)
|
return nil, fmt.Errorf("validating VCEK: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateSNPReport(vcek, idKeyDigest, enforceIDKeyDigest, report, log); err != nil {
|
if err := v.validateSNPReport(ctx, vcek, report, instanceInfo.MAAToken, extraData); err != nil {
|
||||||
return nil, fmt.Errorf("validating SNP report: %w", err)
|
return nil, fmt.Errorf("validating SNP report: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pubArea, err := tpm2.DecodePublic(akPub)
|
pubArea, err := tpm2.DecodePublic(attDoc.Attestation.AkPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = hclAk.validateAk(instanceInfo.RuntimeData, report.ReportData[:], pubArea.RSAParameters); err != nil {
|
if err = v.hclValidator.validateAk(instanceInfo.RuntimeData, report.ReportData[:], pubArea.RSAParameters); err != nil {
|
||||||
return nil, fmt.Errorf("validating HCLAkPub: %w", err)
|
return nil, fmt.Errorf("validating HCLAkPub: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pubArea.Key()
|
return pubArea.Key()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// validateVCEK takes the PEM-encoded X509 certificate VCEK, ASK and ARK and verifies the integrity of the chain.
|
// validateVCEK takes the PEM-encoded X509 certificate VCEK, ASK and ARK and verifies the integrity of the chain.
|
||||||
// ARK (hardcoded) validates ASK (cloud metadata API) validates VCEK (cloud metadata API).
|
// ARK (hardcoded) validates ASK (cloud metadata API) validates VCEK (cloud metadata API).
|
||||||
|
@ -143,9 +158,8 @@ func validateVCEK(vcekRaw []byte, certChain []byte) (*x509.Certificate, error) {
|
||||||
return vcek, nil
|
return vcek, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateSNPReport(
|
func (v *Validator) validateSNPReport(
|
||||||
cert *x509.Certificate, expectedIDKeyDigests idkeydigest.IDKeyDigests, enforceIDKeyDigest bool,
|
ctx context.Context, cert *x509.Certificate, report snpAttestationReport, maaToken string, extraData []byte,
|
||||||
report snpAttestationReport, log vtpm.AttestationLogger,
|
|
||||||
) error {
|
) error {
|
||||||
if report.Policy.Debug() {
|
if report.Policy.Debug() {
|
||||||
return errDebugEnabled
|
return errDebugEnabled
|
||||||
|
@ -191,7 +205,7 @@ func validateSNPReport(
|
||||||
}
|
}
|
||||||
|
|
||||||
hasExpectedIDKeyDigest := false
|
hasExpectedIDKeyDigest := false
|
||||||
for _, digest := range expectedIDKeyDigests {
|
for _, digest := range v.idKeyDigests {
|
||||||
if bytes.Equal(digest, report.IDKeyDigest[:]) {
|
if bytes.Equal(digest, report.IDKeyDigest[:]) {
|
||||||
hasExpectedIDKeyDigest = true
|
hasExpectedIDKeyDigest = true
|
||||||
break
|
break
|
||||||
|
@ -199,11 +213,14 @@ func validateSNPReport(
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasExpectedIDKeyDigest {
|
if !hasExpectedIDKeyDigest {
|
||||||
if enforceIDKeyDigest {
|
switch v.enforceIDKeyDigest {
|
||||||
return &idKeyError{report.IDKeyDigest[:], expectedIDKeyDigests}
|
case idkeydigest.MAAFallback:
|
||||||
}
|
v.log.Infof("configured idkeydigests %x don't contain reported idkeydigest %x, falling back to MAA validation", v.idKeyDigests, report.IDKeyDigest[:])
|
||||||
if log != nil {
|
return v.maa.validateToken(ctx, v.maaURL, maaToken, extraData)
|
||||||
log.Warnf("configured idkeydigests %x doesn't contain reported idkeydigest %x", expectedIDKeyDigests, report.IDKeyDigest[:])
|
case idkeydigest.WarnOnly:
|
||||||
|
v.log.Warnf("configured idkeydigests %x don't contain reported idkeydigest %x", v.idKeyDigests, report.IDKeyDigest[:])
|
||||||
|
default:
|
||||||
|
return &idKeyError{report.IDKeyDigest[:], v.idKeyDigests}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,6 +287,7 @@ type azureInstanceInfo struct {
|
||||||
CertChain []byte
|
CertChain []byte
|
||||||
AttestationReport []byte
|
AttestationReport []byte
|
||||||
RuntimeData []byte
|
RuntimeData []byte
|
||||||
|
MAAToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateAk validates that the attestation key from the TPM is trustworthy. The steps are:
|
// validateAk validates that the attestation key from the TPM is trustworthy. The steps are:
|
||||||
|
@ -320,10 +338,10 @@ func (a *azureInstanceInfo) validateAk(runtimeDataRaw []byte, reportData []byte,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HCLAkValidator validates an attestation key issued by the Host Compatibility Layer (HCL).
|
// hclAkValidator validates an attestation key issued by the Host Compatibility Layer (HCL).
|
||||||
// The HCL is written by Azure, and sits between the Hypervisor and CVM OS.
|
// The HCL is written by Azure, and sits between the Hypervisor and CVM OS.
|
||||||
// The HCL runs in the protected context of the CVM.
|
// The HCL runs in the protected context of the CVM.
|
||||||
type HCLAkValidator interface {
|
type hclAkValidator interface {
|
||||||
validateAk(runtimeDataRaw []byte, reportData []byte, rsaParameters *tpm2.RSAParams) error
|
validateAk(runtimeDataRaw []byte, reportData []byte, rsaParameters *tpm2.RSAParams) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,3 +431,16 @@ type akPub struct {
|
||||||
type runtimeData struct {
|
type runtimeData struct {
|
||||||
Keys []akPub
|
Keys []akPub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nopAttestationLogger is a no-op implementation of AttestationLogger.
|
||||||
|
type nopAttestationLogger struct{}
|
||||||
|
|
||||||
|
// Infof is a no-op.
|
||||||
|
func (nopAttestationLogger) Infof(string, ...interface{}) {}
|
||||||
|
|
||||||
|
// Warnf is a no-op.
|
||||||
|
func (nopAttestationLogger) Warnf(string, ...interface{}) {}
|
||||||
|
|
||||||
|
type maaValidator interface {
|
||||||
|
validateToken(ctx context.Context, maaURL string, token string, extraData []byte) error
|
||||||
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -33,10 +33,12 @@ go_test(
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/attestation/measurements",
|
"//internal/attestation/measurements",
|
||||||
"//internal/attestation/simulator",
|
"//internal/attestation/simulator",
|
||||||
|
"//internal/attestation/vtpm",
|
||||||
"//internal/crypto",
|
"//internal/crypto",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"@com_github_google_go_tpm//tpm2",
|
"@com_github_google_go_tpm//tpm2",
|
||||||
"@com_github_google_go_tpm_tools//client",
|
"@com_github_google_go_tpm_tools//client",
|
||||||
|
"@com_github_google_go_tpm_tools//proto/attest",
|
||||||
"@com_github_stretchr_testify//assert",
|
"@com_github_stretchr_testify//assert",
|
||||||
"@com_github_stretchr_testify//require",
|
"@com_github_stretchr_testify//require",
|
||||||
],
|
],
|
||||||
|
|
|
@ -14,7 +14,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/oid"
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
|
@ -55,7 +54,7 @@ type akSigner struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAttestationCert returns the DER encoded certificate of the TPM's attestation key and it's CA.
|
// getAttestationCert returns the DER encoded certificate of the TPM's attestation key and it's CA.
|
||||||
func (i *Issuer) getAttestationCert(tpm io.ReadWriteCloser) ([]byte, error) {
|
func (i *Issuer) getAttestationCert(ctx context.Context, tpm io.ReadWriteCloser, _ []byte) ([]byte, error) {
|
||||||
certDER, err := tpm2.NVReadEx(tpm, tpmAkCertIdx, tpm2.HandleOwner, "", 0)
|
certDER, err := tpm2.NVReadEx(tpm, tpmAkCertIdx, tpm2.HandleOwner, "", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("reading attestation key certificate from TPM: %w", err)
|
return nil, fmt.Errorf("reading attestation key certificate from TPM: %w", err)
|
||||||
|
@ -71,8 +70,6 @@ func (i *Issuer) getAttestationCert(tpm io.ReadWriteCloser) ([]byte, error) {
|
||||||
// if no CA certificate can be loaded, an error is returned
|
// if no CA certificate can be loaded, an error is returned
|
||||||
var caCert *x509.Certificate
|
var caCert *x509.Certificate
|
||||||
for _, caCertURL := range cert.IssuingCertificateURL {
|
for _, caCertURL := range cert.IssuingCertificateURL {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
|
||||||
defer cancel()
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, caCertURL, nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, caCertURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -8,6 +8,7 @@ package trustedlaunch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
@ -19,9 +20,11 @@ import (
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
"github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
tpmclient "github.com/google/go-tpm-tools/client"
|
tpmclient "github.com/google/go-tpm-tools/client"
|
||||||
|
"github.com/google/go-tpm-tools/proto/attest"
|
||||||
"github.com/google/go-tpm/tpm2"
|
"github.com/google/go-tpm/tpm2"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -183,13 +186,20 @@ func TestGetAttestationCert(t *testing.T) {
|
||||||
issuer := NewIssuer(logger.NewTest(t))
|
issuer := NewIssuer(logger.NewTest(t))
|
||||||
issuer.hClient = newTestClient(tc.crlServer)
|
issuer.hClient = newTestClient(tc.crlServer)
|
||||||
|
|
||||||
certs, err := issuer.getAttestationCert(tpm)
|
certs, err := issuer.getAttestationCert(context.Background(), tpm, nil)
|
||||||
if tc.wantIssueErr {
|
if tc.wantIssueErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
|
attDoc := vtpm.AttestationDocument{
|
||||||
|
InstanceInfo: certs,
|
||||||
|
Attestation: &attest.Attestation{
|
||||||
|
AkPub: akPub,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
validator := NewValidator(measurements.M{}, nil)
|
validator := NewValidator(measurements.M{}, nil)
|
||||||
cert, err := x509.ParseCertificate(rootCert.Raw)
|
cert, err := x509.ParseCertificate(rootCert.Raw)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
@ -197,7 +207,7 @@ func TestGetAttestationCert(t *testing.T) {
|
||||||
roots.AddCert(cert)
|
roots.AddCert(cert)
|
||||||
validator.roots = roots
|
validator.roots = roots
|
||||||
|
|
||||||
key, err := validator.verifyAttestationKey(akPub, certs)
|
key, err := validator.verifyAttestationKey(context.Background(), attDoc, nil)
|
||||||
if tc.wantValidateErr {
|
if tc.wantValidateErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
package trustedlaunch
|
package trustedlaunch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
@ -49,14 +50,14 @@ func NewValidator(pcrs measurements.M, log vtpm.AttestationLogger) *Validator {
|
||||||
|
|
||||||
// verifyAttestationKey establishes trust in an attestation key.
|
// verifyAttestationKey establishes trust in an attestation key.
|
||||||
// It does so by verifying the certificate chain of the attestation key certificate.
|
// It does so by verifying the certificate chain of the attestation key certificate.
|
||||||
func (v *Validator) verifyAttestationKey(akPub, instanceInfo []byte) (crypto.PublicKey, error) {
|
func (v *Validator) verifyAttestationKey(_ context.Context, attDoc vtpm.AttestationDocument, _ []byte) (crypto.PublicKey, error) {
|
||||||
pubArea, err := tpm2.DecodePublic(akPub)
|
pubArea, err := tpm2.DecodePublic(attDoc.Attestation.AkPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("decoding attestation key public area: %w", err)
|
return nil, fmt.Errorf("decoding attestation key public area: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var akSigner akSigner
|
var akSigner akSigner
|
||||||
if err := json.Unmarshal(instanceInfo, &akSigner); err != nil {
|
if err := json.Unmarshal(attDoc.InstanceInfo, &akSigner); err != nil {
|
||||||
return nil, fmt.Errorf("unmarshaling attestation key signer info: %w", err)
|
return nil, fmt.Errorf("unmarshaling attestation key signer info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ go_test(
|
||||||
srcs = ["choose_test.go"],
|
srcs = ["choose_test.go"],
|
||||||
embed = [":choose"],
|
embed = [":choose"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//internal/attestation/idkeydigest",
|
||||||
"//internal/oid",
|
"//internal/oid",
|
||||||
"@com_github_stretchr_testify//assert",
|
"@com_github_stretchr_testify//assert",
|
||||||
"@com_github_stretchr_testify//require",
|
"@com_github_stretchr_testify//require",
|
||||||
|
|
|
@ -43,9 +43,7 @@ func Issuer(variant oid.Getter, log vtpm.AttestationLogger) (atls.Issuer, error)
|
||||||
|
|
||||||
// Validator returns the validator for the given variant.
|
// Validator returns the validator for the given variant.
|
||||||
func Validator(
|
func Validator(
|
||||||
variant oid.Getter, measurements measurements.M,
|
variant oid.Getter, measurements measurements.M, idKeyCfg idkeydigest.Config, log vtpm.AttestationLogger,
|
||||||
idKeyDigest idkeydigest.IDKeyDigests, enfoceIDKeyDigest bool,
|
|
||||||
log vtpm.AttestationLogger,
|
|
||||||
) (atls.Validator, error) {
|
) (atls.Validator, error) {
|
||||||
switch variant {
|
switch variant {
|
||||||
case oid.AWSNitroTPM{}:
|
case oid.AWSNitroTPM{}:
|
||||||
|
@ -53,7 +51,7 @@ func Validator(
|
||||||
case oid.AzureTrustedLaunch{}:
|
case oid.AzureTrustedLaunch{}:
|
||||||
return trustedlaunch.NewValidator(measurements, log), nil
|
return trustedlaunch.NewValidator(measurements, log), nil
|
||||||
case oid.AzureSEVSNP{}:
|
case oid.AzureSEVSNP{}:
|
||||||
return snp.NewValidator(measurements, idKeyDigest, enfoceIDKeyDigest, log), nil
|
return snp.NewValidator(measurements, idKeyCfg, log), nil
|
||||||
case oid.GCPSEVES{}:
|
case oid.GCPSEVES{}:
|
||||||
return gcp.NewValidator(measurements, log), nil
|
return gcp.NewValidator(measurements, log), nil
|
||||||
case oid.QEMUVTPM{}:
|
case oid.QEMUVTPM{}:
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/oid"
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -95,7 +96,7 @@ func TestValidator(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
validator, err := Validator(tc.variant, nil, nil, false, nil)
|
validator, err := Validator(tc.variant, nil, idkeydigest.Config{}, nil)
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
|
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
package gcp
|
package gcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
@ -37,12 +38,12 @@ func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getGCEInstanceInfo fetches VM metadata used for attestation.
|
// getGCEInstanceInfo fetches VM metadata used for attestation.
|
||||||
func getGCEInstanceInfo(client gcpMetadataClient) func(io.ReadWriteCloser) ([]byte, error) {
|
func getGCEInstanceInfo(client gcpMetadataClient) func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) {
|
||||||
// Ideally we would want to use the endorsement public key certificate
|
// Ideally we would want to use the endorsement public key certificate
|
||||||
// However, this is not available on GCE instances
|
// However, this is not available on GCE instances
|
||||||
// Workaround: Provide ShieldedVM instance info
|
// Workaround: Provide ShieldedVM instance info
|
||||||
// The attestating party can request the VMs signing key using Google's API
|
// The attestating party can request the VMs signing key using Google's API
|
||||||
return func(io.ReadWriteCloser) ([]byte, error) {
|
return func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) {
|
||||||
projectID, err := client.projectID()
|
projectID, err := client.projectID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("unable to fetch projectID")
|
return nil, errors.New("unable to fetch projectID")
|
||||||
|
|
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
package gcp
|
package gcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
@ -65,7 +66,7 @@ func TestGetGCEInstanceInfo(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
var tpm io.ReadWriteCloser
|
var tpm io.ReadWriteCloser
|
||||||
|
|
||||||
out, err := getGCEInstanceInfo(tc.client)(tpm)
|
out, err := getGCEInstanceInfo(tc.client)(context.Background(), tpm, nil)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
compute "cloud.google.com/go/compute/apiv1"
|
compute "cloud.google.com/go/compute/apiv1"
|
||||||
"cloud.google.com/go/compute/apiv1/computepb"
|
"cloud.google.com/go/compute/apiv1/computepb"
|
||||||
|
@ -31,18 +30,23 @@ const minimumGceVersion = 1
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
oid.GCPSEVES
|
oid.GCPSEVES
|
||||||
*vtpm.Validator
|
*vtpm.Validator
|
||||||
|
|
||||||
|
restClient func(context.Context, ...option.ClientOption) (gcpRestClient, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidator initializes a new GCP validator with the provided PCR values.
|
// NewValidator initializes a new GCP validator with the provided PCR values.
|
||||||
func NewValidator(pcrs measurements.M, log vtpm.AttestationLogger) *Validator {
|
func NewValidator(pcrs measurements.M, log vtpm.AttestationLogger) *Validator {
|
||||||
return &Validator{
|
v := &Validator{
|
||||||
Validator: vtpm.NewValidator(
|
restClient: newInstanceClient,
|
||||||
|
}
|
||||||
|
v.Validator = vtpm.NewValidator(
|
||||||
pcrs,
|
pcrs,
|
||||||
trustedKeyFromGCEAPI(newInstanceClient),
|
v.trustedKeyFromGCEAPI,
|
||||||
validateCVM,
|
validateCVM,
|
||||||
log,
|
log,
|
||||||
),
|
)
|
||||||
}
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
type gcpRestClient interface {
|
type gcpRestClient interface {
|
||||||
|
@ -64,20 +68,18 @@ func newInstanceClient(ctx context.Context, opts ...option.ClientOption) (gcpRes
|
||||||
|
|
||||||
// trustedKeyFromGCEAPI queries the GCE API for a shieldedVM's public signing key.
|
// trustedKeyFromGCEAPI queries the GCE API for a shieldedVM's public signing key.
|
||||||
// This key can be used to verify attestation statements issued by the VM.
|
// This key can be used to verify attestation statements issued by the VM.
|
||||||
func trustedKeyFromGCEAPI(getClient func(ctx context.Context, opts ...option.ClientOption) (gcpRestClient, error)) func(akPub []byte, instanceInfoRaw []byte) (crypto.PublicKey, error) {
|
func (v *Validator) trustedKeyFromGCEAPI(ctx context.Context, attDoc vtpm.AttestationDocument, _ []byte) (crypto.PublicKey, error) {
|
||||||
return func(akPub, instanceInfoRaw []byte) (crypto.PublicKey, error) {
|
client, err := v.restClient(ctx)
|
||||||
var instanceInfo attest.GCEInstanceInfo
|
|
||||||
if err := json.Unmarshal(instanceInfoRaw, &instanceInfo); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
|
||||||
defer cancel()
|
|
||||||
client, err := getClient(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("creating GCE client: %w", err)
|
return nil, fmt.Errorf("creating GCE client: %w", err)
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
|
var instanceInfo attest.GCEInstanceInfo
|
||||||
|
if err := json.Unmarshal(attDoc.InstanceInfo, &instanceInfo); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
instance, err := client.GetShieldedInstanceIdentity(ctx, &computepb.GetShieldedInstanceIdentityInstanceRequest{
|
instance, err := client.GetShieldedInstanceIdentity(ctx, &computepb.GetShieldedInstanceIdentityInstanceRequest{
|
||||||
Instance: instanceInfo.GetInstanceName(),
|
Instance: instanceInfo.GetInstanceName(),
|
||||||
Project: instanceInfo.GetProjectId(),
|
Project: instanceInfo.GetProjectId(),
|
||||||
|
@ -99,7 +101,6 @@ func trustedKeyFromGCEAPI(getClient func(ctx context.Context, opts ...option.Cli
|
||||||
|
|
||||||
return x509.ParsePKIXPublicKey(block.Bytes)
|
return x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// validateCVM checks that the machine state represents a GCE AMD-SEV VM.
|
// validateCVM checks that the machine state represents a GCE AMD-SEV VM.
|
||||||
func validateCVM(_ vtpm.AttestationDocument, state *attest.MachineState) error {
|
func validateCVM(_ vtpm.AttestationDocument, state *attest.MachineState) error {
|
||||||
|
|
|
@ -146,7 +146,12 @@ Y+t5OxL3kL15VzY1Ob0d5cMCAwEAAQ==
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
out, err := trustedKeyFromGCEAPI(tc.getClient)(nil, tc.instanceInfo)
|
v := &Validator{
|
||||||
|
restClient: tc.getClient,
|
||||||
|
}
|
||||||
|
attDoc := vtpm.AttestationDocument{InstanceInfo: tc.instanceInfo}
|
||||||
|
|
||||||
|
out, err := v.trustedKeyFromGCEAPI(context.Background(), attDoc, nil)
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
|
|
@ -3,7 +3,10 @@ load("//bazel/go:go_test.bzl", "go_test")
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "idkeydigest",
|
name = "idkeydigest",
|
||||||
srcs = ["idkeydigest.go"],
|
srcs = [
|
||||||
|
"enforceidkeydigest_string.go",
|
||||||
|
"idkeydigest.go",
|
||||||
|
],
|
||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = ["//internal/cloud/cloudprovider"],
|
deps = ["//internal/cloud/cloudprovider"],
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Code generated by "stringer -type=EnforceIDKeyDigest"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package idkeydigest
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[Unknown-0]
|
||||||
|
_ = x[StrictChecking-1]
|
||||||
|
_ = x[MAAFallback-2]
|
||||||
|
_ = x[WarnOnly-3]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _EnforceIDKeyDigest_name = "UnknownStrictCheckingMAAFallbackWarnOnly"
|
||||||
|
|
||||||
|
var _EnforceIDKeyDigest_index = [...]uint8{0, 7, 21, 32, 40}
|
||||||
|
|
||||||
|
func (i EnforceIDKeyDigest) String() string {
|
||||||
|
if i >= EnforceIDKeyDigest(len(_EnforceIDKeyDigest_index)-1) {
|
||||||
|
return "EnforceIDKeyDigest(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _EnforceIDKeyDigest_name[_EnforceIDKeyDigest_index[i]:_EnforceIDKeyDigest_index[i+1]]
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ Copyright (c) Edgeless Systems GmbH
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package idkeydigest contains policies and type definitions
|
||||||
|
// for checking the ID Key Digest value in SEV-SNP attestation.
|
||||||
package idkeydigest
|
package idkeydigest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -11,10 +13,105 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Config contains the configuration for ID Key Digest validation.
|
||||||
|
type Config struct {
|
||||||
|
IDKeyDigests IDKeyDigests `json:"idKeyDigests"`
|
||||||
|
EnforcementPolicy EnforceIDKeyDigest `json:"enforcementPolicy"`
|
||||||
|
MAAURL string `json:"maaURL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate stringer -type=EnforceIDKeyDigest
|
||||||
|
|
||||||
|
// EnforceIDKeyDigest defines the behavior of the validator when the ID key digest is not found in the expected list.
|
||||||
|
type EnforceIDKeyDigest uint32
|
||||||
|
|
||||||
|
// TODO: Decide on final value naming.
|
||||||
|
const (
|
||||||
|
// Unknown is reserved for invalid configurations.
|
||||||
|
Unknown EnforceIDKeyDigest = iota
|
||||||
|
// StrictChecking will return an error if the ID key digest is not found in the expected list.
|
||||||
|
StrictChecking
|
||||||
|
// MAAFallback attempts to verify the attestation using Microsoft Azure Attestation (MAA),
|
||||||
|
// if the ID key digest is not found in the expected list.
|
||||||
|
MAAFallback
|
||||||
|
// WarnOnly logs a warning if the ID key digest is not found in the expected list.
|
||||||
|
// No error is returned.
|
||||||
|
WarnOnly
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (e *EnforceIDKeyDigest) UnmarshalJSON(b []byte) error {
|
||||||
|
return e.unmarshal(func(val any) error {
|
||||||
|
return json.Unmarshal(b, val)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
|
func (e EnforceIDKeyDigest) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(e.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
func (e *EnforceIDKeyDigest) UnmarshalYAML(unmarshal func(any) error) error {
|
||||||
|
return e.unmarshal(unmarshal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalYAML implements the yaml.Marshaler interface.
|
||||||
|
func (e EnforceIDKeyDigest) MarshalYAML() (any, error) {
|
||||||
|
return e.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EnforceIDKeyDigest) unmarshal(unmarshalFunc func(any) error) error {
|
||||||
|
// Check for legacy format: EnforceIDKeyDigest might be a boolean.
|
||||||
|
// If set to true, the value will be set to StrictChecking.
|
||||||
|
// If set to false, the value will be set to WarnOnly.
|
||||||
|
var legacyEnforce bool
|
||||||
|
legacyErr := unmarshalFunc(&legacyEnforce)
|
||||||
|
if legacyErr == nil {
|
||||||
|
if legacyEnforce {
|
||||||
|
*e = StrictChecking
|
||||||
|
} else {
|
||||||
|
*e = WarnOnly
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var enforce string
|
||||||
|
if err := unmarshalFunc(&enforce); err != nil {
|
||||||
|
return errors.Join(
|
||||||
|
err,
|
||||||
|
fmt.Errorf("trying legacy format: %w", legacyErr),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
*e = EnforcePolicyFromString(enforce)
|
||||||
|
if *e == Unknown {
|
||||||
|
return fmt.Errorf("unknown EnforceIDKeyDigest value: %q", enforce)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnforcePolicyFromString returns EnforceIDKeyDigest from string.
|
||||||
|
func EnforcePolicyFromString(s string) EnforceIDKeyDigest {
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
switch s {
|
||||||
|
case "strictchecking":
|
||||||
|
return StrictChecking
|
||||||
|
case "maafallback":
|
||||||
|
return MAAFallback
|
||||||
|
case "warnonly":
|
||||||
|
return WarnOnly
|
||||||
|
default:
|
||||||
|
return Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IDKeyDigests is a list of trusted digest values for the ID key.
|
// IDKeyDigests is a list of trusted digest values for the ID key.
|
||||||
type IDKeyDigests [][]byte
|
type IDKeyDigests [][]byte
|
||||||
|
|
||||||
|
|
|
@ -117,3 +117,126 @@ func TestUnmarshal(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnforceIDKeyDigestMarshal(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input EnforceIDKeyDigest
|
||||||
|
wantJSON string
|
||||||
|
wantYAML string
|
||||||
|
}{
|
||||||
|
"strict": {
|
||||||
|
input: StrictChecking,
|
||||||
|
wantJSON: `"StrictChecking"`,
|
||||||
|
wantYAML: "StrictChecking",
|
||||||
|
},
|
||||||
|
"maaFallback": {
|
||||||
|
input: MAAFallback,
|
||||||
|
wantJSON: `"MAAFallback"`,
|
||||||
|
wantYAML: "MAAFallback",
|
||||||
|
},
|
||||||
|
"warnOnly": {
|
||||||
|
input: WarnOnly,
|
||||||
|
wantJSON: `"WarnOnly"`,
|
||||||
|
wantYAML: "WarnOnly",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
{
|
||||||
|
// YAML
|
||||||
|
yaml, err := yaml.Marshal(tc.input)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.YAMLEq(tc.wantYAML, string(yaml))
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// JSON
|
||||||
|
json, err := json.Marshal(tc.input)
|
||||||
|
require.NoError(err)
|
||||||
|
assert.JSONEq(tc.wantJSON, string(json))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnforceIDKeyDigestUnmarshal(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
inputJSON string
|
||||||
|
inputYAML string
|
||||||
|
want EnforceIDKeyDigest
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
"strict": {
|
||||||
|
inputJSON: `"StrictChecking"`,
|
||||||
|
inputYAML: "StrictChecking",
|
||||||
|
want: StrictChecking,
|
||||||
|
},
|
||||||
|
"maaFallback": {
|
||||||
|
inputJSON: `"MAAFallback"`,
|
||||||
|
inputYAML: "MAAFallback",
|
||||||
|
want: MAAFallback,
|
||||||
|
},
|
||||||
|
"warnOnly": {
|
||||||
|
inputJSON: `"WarnOnly"`,
|
||||||
|
inputYAML: "WarnOnly",
|
||||||
|
want: WarnOnly,
|
||||||
|
},
|
||||||
|
"legacyTrue": {
|
||||||
|
inputJSON: `true`,
|
||||||
|
inputYAML: "true",
|
||||||
|
want: StrictChecking,
|
||||||
|
},
|
||||||
|
"legacyFalse": {
|
||||||
|
inputJSON: `false`,
|
||||||
|
inputYAML: "false",
|
||||||
|
want: WarnOnly,
|
||||||
|
},
|
||||||
|
"invalid": {
|
||||||
|
inputJSON: `"invalid"`,
|
||||||
|
inputYAML: "invalid",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
"invalidType": {
|
||||||
|
inputJSON: `{"object": "invalid"}`,
|
||||||
|
inputYAML: "object: invalid",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
{
|
||||||
|
// YAML
|
||||||
|
var got EnforceIDKeyDigest
|
||||||
|
err := yaml.Unmarshal([]byte(tc.inputYAML), &got)
|
||||||
|
if tc.wantErr {
|
||||||
|
assert.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Equal(tc.want, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// JSON
|
||||||
|
var got EnforceIDKeyDigest
|
||||||
|
err := json.Unmarshal([]byte(tc.inputJSON), &got)
|
||||||
|
if tc.wantErr {
|
||||||
|
assert.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Equal(tc.want, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
package qemu
|
package qemu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||||
|
@ -26,7 +27,7 @@ func NewIssuer(log vtpm.AttestationLogger) *Issuer {
|
||||||
Issuer: vtpm.NewIssuer(
|
Issuer: vtpm.NewIssuer(
|
||||||
vtpm.OpenVTPM,
|
vtpm.OpenVTPM,
|
||||||
tpmclient.AttestationKeyRSA,
|
tpmclient.AttestationKeyRSA,
|
||||||
func(tpm io.ReadWriteCloser) ([]byte, error) { return nil, nil },
|
func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) { return nil, nil },
|
||||||
log,
|
log,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
package qemu
|
package qemu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
|
@ -35,8 +36,8 @@ func NewValidator(pcrs measurements.M, log vtpm.AttestationLogger) *Validator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// unconditionalTrust returns the given public key as the trusted attestation key.
|
// unconditionalTrust returns the given public key as the trusted attestation key.
|
||||||
func unconditionalTrust(akPub, _ []byte) (crypto.PublicKey, error) {
|
func unconditionalTrust(_ context.Context, attDoc vtpm.AttestationDocument, _ []byte) (crypto.PublicKey, error) {
|
||||||
pubArea, err := tpm2.DecodePublic(akPub)
|
pubArea, err := tpm2.DecodePublic(attDoc.Attestation.AkPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package vtpm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -58,9 +59,9 @@ type (
|
||||||
// GetTPMAttestationKey loads a TPM key to perform attestation.
|
// GetTPMAttestationKey loads a TPM key to perform attestation.
|
||||||
GetTPMAttestationKey func(tpm io.ReadWriter) (*tpmClient.Key, error)
|
GetTPMAttestationKey func(tpm io.ReadWriter) (*tpmClient.Key, error)
|
||||||
// GetTPMTrustedAttestationPublicKey verifies and returns the attestation public key.
|
// GetTPMTrustedAttestationPublicKey verifies and returns the attestation public key.
|
||||||
GetTPMTrustedAttestationPublicKey func(akPub []byte, instanceInfo []byte) (crypto.PublicKey, error)
|
GetTPMTrustedAttestationPublicKey func(context.Context, AttestationDocument, []byte) (crypto.PublicKey, error)
|
||||||
// GetInstanceInfo returns VM metdata.
|
// GetInstanceInfo returns VM metdata.
|
||||||
GetInstanceInfo func(tpm io.ReadWriteCloser) ([]byte, error)
|
GetInstanceInfo func(ctx context.Context, tpm io.ReadWriteCloser, extraData []byte) ([]byte, error)
|
||||||
// ValidateCVM validates confidential computing capabilities of the instance issuing the attestation.
|
// ValidateCVM validates confidential computing capabilities of the instance issuing the attestation.
|
||||||
ValidateCVM func(attestation AttestationDocument, state *attest.MachineState) error
|
ValidateCVM func(attestation AttestationDocument, state *attest.MachineState) error
|
||||||
)
|
)
|
||||||
|
@ -135,7 +136,7 @@ func (i *Issuer) Issue(userData []byte, nonce []byte) (res []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch instance info of the VM
|
// Fetch instance info of the VM
|
||||||
instanceInfo, err := i.getInstanceInfo(tpm)
|
instanceInfo, err := i.getInstanceInfo(context.TODO(), tpm, extraData) // TODO(daniel-weisse): update Issue/Validate to use context
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("fetching instance info: %w", err)
|
return nil, fmt.Errorf("fetching instance info: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -193,8 +194,10 @@ func (v *Validator) Validate(attDocRaw []byte, nonce []byte) (userData []byte, e
|
||||||
return nil, fmt.Errorf("unmarshaling TPM attestation document: %w", err)
|
return nil, fmt.Errorf("unmarshaling TPM attestation document: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extraData := makeExtraData(attDoc.UserData, nonce)
|
||||||
|
|
||||||
// Verify and retrieve the trusted attestation public key using the provided instance info
|
// Verify and retrieve the trusted attestation public key using the provided instance info
|
||||||
aKP, err := v.getTrustedKey(attDoc.Attestation.AkPub, attDoc.InstanceInfo)
|
aKP, err := v.getTrustedKey(context.TODO(), attDoc, extraData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("validating attestation public key: %w", err)
|
return nil, fmt.Errorf("validating attestation public key: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -203,7 +206,7 @@ func (v *Validator) Validate(attDocRaw []byte, nonce []byte) (userData []byte, e
|
||||||
state, err := tpmServer.VerifyAttestation(
|
state, err := tpmServer.VerifyAttestation(
|
||||||
attDoc.Attestation,
|
attDoc.Attestation,
|
||||||
tpmServer.VerifyOpts{
|
tpmServer.VerifyOpts{
|
||||||
Nonce: makeExtraData(attDoc.UserData, nonce),
|
Nonce: extraData,
|
||||||
TrustedAKs: []crypto.PublicKey{aKP},
|
TrustedAKs: []crypto.PublicKey{aKP},
|
||||||
AllowSHA1: false,
|
AllowSHA1: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
package vtpm
|
package vtpm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -51,7 +52,7 @@ func (s simTPMWithEventLog) EventLog() ([]byte, error) {
|
||||||
return header, nil
|
return header, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fakeGetInstanceInfo(_ io.ReadWriteCloser) ([]byte, error) {
|
func fakeGetInstanceInfo(_ context.Context, _ io.ReadWriteCloser, _ []byte) ([]byte, error) {
|
||||||
return []byte("unit-test"), nil
|
return []byte("unit-test"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +60,8 @@ func TestValidate(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
fakeValidateCVM := func(AttestationDocument, *attest.MachineState) error { return nil }
|
fakeValidateCVM := func(AttestationDocument, *attest.MachineState) error { return nil }
|
||||||
fakeGetTrustedKey := func(aKPub, instanceInfo []byte) (crypto.PublicKey, error) {
|
fakeGetTrustedKey := func(_ context.Context, attDoc AttestationDocument, _ []byte) (crypto.PublicKey, error) {
|
||||||
pubArea, err := tpm2.DecodePublic(aKPub)
|
pubArea, err := tpm2.DecodePublic(attDoc.Attestation.AkPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -175,7 +176,7 @@ func TestValidate(t *testing.T) {
|
||||||
"untrusted attestation public key": {
|
"untrusted attestation public key": {
|
||||||
validator: NewValidator(
|
validator: NewValidator(
|
||||||
testExpectedPCRs,
|
testExpectedPCRs,
|
||||||
func(akPub, instanceInfo []byte) (crypto.PublicKey, error) {
|
func(context.Context, AttestationDocument, []byte) (crypto.PublicKey, error) {
|
||||||
return nil, errors.New("untrusted")
|
return nil, errors.New("untrusted")
|
||||||
},
|
},
|
||||||
fakeValidateCVM, warnLog),
|
fakeValidateCVM, warnLog),
|
||||||
|
@ -301,7 +302,7 @@ func TestFailIssuer(t *testing.T) {
|
||||||
issuer: NewIssuer(
|
issuer: NewIssuer(
|
||||||
newSimTPMWithEventLog,
|
newSimTPMWithEventLog,
|
||||||
tpmclient.AttestationKeyRSA,
|
tpmclient.AttestationKeyRSA,
|
||||||
func(io.ReadWriteCloser) ([]byte, error) { return nil, errors.New("failure") },
|
func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) { return nil, errors.New("failure") },
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
userData: []byte("Constellation"),
|
userData: []byte("Constellation"),
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
||||||
|
@ -51,12 +50,8 @@ func New(ctx context.Context) (*Cloud, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("loading credentials: %w", err)
|
return nil, fmt.Errorf("loading credentials: %w", err)
|
||||||
}
|
}
|
||||||
// The default http client may use a system-wide proxy and it is recommended to disable the proxy explicitly:
|
|
||||||
// https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#proxies
|
imdsAPI := NewIMDSClient()
|
||||||
// See also: https://github.com/microsoft/azureimds/blob/master/imdssample.go#L10
|
|
||||||
imdsAPI := imdsClient{
|
|
||||||
client: &http.Client{Transport: &http.Transport{Proxy: nil}},
|
|
||||||
}
|
|
||||||
subscriptionID, err := imdsAPI.subscriptionID(ctx)
|
subscriptionID, err := imdsAPI.subscriptionID(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("retrieving subscription ID: %w", err)
|
return nil, fmt.Errorf("retrieving subscription ID: %w", err)
|
||||||
|
@ -91,7 +86,7 @@ func New(ctx context.Context) (*Cloud, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Cloud{
|
return &Cloud{
|
||||||
imds: &imdsAPI,
|
imds: imdsAPI,
|
||||||
netIfacAPI: networkInterfacesAPI,
|
netIfacAPI: networkInterfacesAPI,
|
||||||
virtNetAPI: virtualNetworksAPI,
|
virtNetAPI: virtualNetworksAPI,
|
||||||
secGroupAPI: securityGroupsAPI,
|
secGroupAPI: securityGroupsAPI,
|
||||||
|
|
|
@ -28,15 +28,42 @@ const (
|
||||||
maxCacheAge = 12 * time.Hour
|
maxCacheAge = 12 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
type imdsClient struct {
|
// IMDSClient is a client for the Azure Instance Metadata Service.
|
||||||
|
type IMDSClient struct {
|
||||||
client *http.Client
|
client *http.Client
|
||||||
|
|
||||||
cache metadataResponse
|
cache metadataResponse
|
||||||
cacheTime time.Time
|
cacheTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewIMDSClient creates a new IMDSClient.
|
||||||
|
func NewIMDSClient() *IMDSClient {
|
||||||
|
// The default http client may use a system-wide proxy and it is recommended to disable the proxy explicitly:
|
||||||
|
// https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#proxies
|
||||||
|
// See also: https://github.com/microsoft/azureimds/blob/master/imdssample.go#L10
|
||||||
|
return &IMDSClient{
|
||||||
|
client: &http.Client{Transport: &http.Transport{Proxy: nil}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tags returns the tags of the instance the function is called from.
|
||||||
|
func (c *IMDSClient) Tags(ctx context.Context) (map[string]string, error) {
|
||||||
|
if c.timeForUpdate() || len(c.cache.Compute.Tags) == 0 {
|
||||||
|
if err := c.update(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := make(map[string]string, len(c.cache.Compute.Tags))
|
||||||
|
for _, tag := range c.cache.Compute.Tags {
|
||||||
|
tags[tag.Name] = tag.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags, nil
|
||||||
|
}
|
||||||
|
|
||||||
// providerID returns the provider ID of the instance the function is called from.
|
// providerID returns the provider ID of the instance the function is called from.
|
||||||
func (c *imdsClient) providerID(ctx context.Context) (string, error) {
|
func (c *IMDSClient) providerID(ctx context.Context) (string, error) {
|
||||||
if c.timeForUpdate() || c.cache.Compute.ResourceID == "" {
|
if c.timeForUpdate() || c.cache.Compute.ResourceID == "" {
|
||||||
if err := c.update(ctx); err != nil {
|
if err := c.update(ctx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -50,7 +77,7 @@ func (c *imdsClient) providerID(ctx context.Context) (string, error) {
|
||||||
return c.cache.Compute.ResourceID, nil
|
return c.cache.Compute.ResourceID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *imdsClient) name(ctx context.Context) (string, error) {
|
func (c *IMDSClient) name(ctx context.Context) (string, error) {
|
||||||
if c.timeForUpdate() || c.cache.Compute.OSProfile.ComputerName == "" {
|
if c.timeForUpdate() || c.cache.Compute.OSProfile.ComputerName == "" {
|
||||||
if err := c.update(ctx); err != nil {
|
if err := c.update(ctx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -66,7 +93,7 @@ func (c *imdsClient) name(ctx context.Context) (string, error) {
|
||||||
|
|
||||||
// subscriptionID returns the subscription ID of the instance the function
|
// subscriptionID returns the subscription ID of the instance the function
|
||||||
// is called from.
|
// is called from.
|
||||||
func (c *imdsClient) subscriptionID(ctx context.Context) (string, error) {
|
func (c *IMDSClient) subscriptionID(ctx context.Context) (string, error) {
|
||||||
if c.timeForUpdate() || c.cache.Compute.SubscriptionID == "" {
|
if c.timeForUpdate() || c.cache.Compute.SubscriptionID == "" {
|
||||||
if err := c.update(ctx); err != nil {
|
if err := c.update(ctx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -82,7 +109,7 @@ func (c *imdsClient) subscriptionID(ctx context.Context) (string, error) {
|
||||||
|
|
||||||
// resourceGroup returns the resource group of the instance the function
|
// resourceGroup returns the resource group of the instance the function
|
||||||
// is called from.
|
// is called from.
|
||||||
func (c *imdsClient) resourceGroup(ctx context.Context) (string, error) {
|
func (c *IMDSClient) resourceGroup(ctx context.Context) (string, error) {
|
||||||
if c.timeForUpdate() || c.cache.Compute.ResourceGroup == "" {
|
if c.timeForUpdate() || c.cache.Compute.ResourceGroup == "" {
|
||||||
if err := c.update(ctx); err != nil {
|
if err := c.update(ctx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -98,7 +125,7 @@ func (c *imdsClient) resourceGroup(ctx context.Context) (string, error) {
|
||||||
|
|
||||||
// uid returns the UID of the cluster, based on the tags on the instance
|
// uid returns the UID of the cluster, based on the tags on the instance
|
||||||
// the function is called from, which are inherited from the scale set.
|
// the function is called from, which are inherited from the scale set.
|
||||||
func (c *imdsClient) uid(ctx context.Context) (string, error) {
|
func (c *IMDSClient) uid(ctx context.Context) (string, error) {
|
||||||
if c.timeForUpdate() || len(c.cache.Compute.Tags) == 0 {
|
if c.timeForUpdate() || len(c.cache.Compute.Tags) == 0 {
|
||||||
if err := c.update(ctx); err != nil {
|
if err := c.update(ctx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -116,7 +143,7 @@ func (c *imdsClient) uid(ctx context.Context) (string, error) {
|
||||||
|
|
||||||
// initSecretHash returns the hash of the init secret of the cluster, based on the tags on the instance
|
// initSecretHash returns the hash of the init secret of the cluster, based on the tags on the instance
|
||||||
// the function is called from, which are inherited from the scale set.
|
// the function is called from, which are inherited from the scale set.
|
||||||
func (c *imdsClient) initSecretHash(ctx context.Context) (string, error) {
|
func (c *IMDSClient) initSecretHash(ctx context.Context) (string, error) {
|
||||||
if c.timeForUpdate() || len(c.cache.Compute.Tags) == 0 {
|
if c.timeForUpdate() || len(c.cache.Compute.Tags) == 0 {
|
||||||
if err := c.update(ctx); err != nil {
|
if err := c.update(ctx); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -133,7 +160,7 @@ func (c *imdsClient) initSecretHash(ctx context.Context) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// role returns the role of the instance the function is called from.
|
// role returns the role of the instance the function is called from.
|
||||||
func (c *imdsClient) role(ctx context.Context) (role.Role, error) {
|
func (c *IMDSClient) role(ctx context.Context) (role.Role, error) {
|
||||||
if c.timeForUpdate() || len(c.cache.Compute.Tags) == 0 {
|
if c.timeForUpdate() || len(c.cache.Compute.Tags) == 0 {
|
||||||
if err := c.update(ctx); err != nil {
|
if err := c.update(ctx); err != nil {
|
||||||
return role.Unknown, err
|
return role.Unknown, err
|
||||||
|
@ -150,12 +177,12 @@ func (c *imdsClient) role(ctx context.Context) (role.Role, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeForUpdate checks whether an update is needed due to cache age.
|
// timeForUpdate checks whether an update is needed due to cache age.
|
||||||
func (c *imdsClient) timeForUpdate() bool {
|
func (c *IMDSClient) timeForUpdate() bool {
|
||||||
return time.Since(c.cacheTime) > maxCacheAge
|
return time.Since(c.cacheTime) > maxCacheAge
|
||||||
}
|
}
|
||||||
|
|
||||||
// update updates instance metadata from the azure imds API.
|
// update updates instance metadata from the azure imds API.
|
||||||
func (c *imdsClient) update(ctx context.Context) error {
|
func (c *IMDSClient) update(ctx context.Context) error {
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, imdsURL, http.NoBody)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, imdsURL, http.NoBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -92,6 +92,11 @@ func TestIMDSClient(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultWantTags := map[string]string{
|
||||||
|
cloud.TagUID: "uid",
|
||||||
|
cloud.TagRole: "worker",
|
||||||
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
server httpBufconnServer
|
server httpBufconnServer
|
||||||
wantProviderIDErr bool
|
wantProviderIDErr bool
|
||||||
|
@ -106,6 +111,8 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantName string
|
wantName string
|
||||||
wantSubscriptionErr bool
|
wantSubscriptionErr bool
|
||||||
wantSubscriptionID string
|
wantSubscriptionID string
|
||||||
|
wantTagsErr bool
|
||||||
|
wantTags map[string]string
|
||||||
}{
|
}{
|
||||||
"metadata response parsed": {
|
"metadata response parsed": {
|
||||||
server: newHTTPBufconnServerWithMetadataResponse(response),
|
server: newHTTPBufconnServerWithMetadataResponse(response),
|
||||||
|
@ -115,6 +122,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantRole: role.Worker,
|
wantRole: role.Worker,
|
||||||
wantName: "computer-name",
|
wantName: "computer-name",
|
||||||
wantSubscriptionID: "subscription-id",
|
wantSubscriptionID: "subscription-id",
|
||||||
|
wantTags: defaultWantTags,
|
||||||
},
|
},
|
||||||
"metadata response without resource ID": {
|
"metadata response without resource ID": {
|
||||||
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutID),
|
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutID),
|
||||||
|
@ -124,6 +132,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantRole: role.Worker,
|
wantRole: role.Worker,
|
||||||
wantName: "computer-name",
|
wantName: "computer-name",
|
||||||
wantSubscriptionID: "subscription-id",
|
wantSubscriptionID: "subscription-id",
|
||||||
|
wantTags: defaultWantTags,
|
||||||
},
|
},
|
||||||
"metadata response without UID tag": {
|
"metadata response without UID tag": {
|
||||||
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutUID),
|
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutUID),
|
||||||
|
@ -133,6 +142,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantRole: role.Worker,
|
wantRole: role.Worker,
|
||||||
wantName: "computer-name",
|
wantName: "computer-name",
|
||||||
wantSubscriptionID: "subscription-id",
|
wantSubscriptionID: "subscription-id",
|
||||||
|
wantTags: map[string]string{cloud.TagRole: "worker"},
|
||||||
},
|
},
|
||||||
"metadata response without role tag": {
|
"metadata response without role tag": {
|
||||||
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutRole),
|
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutRole),
|
||||||
|
@ -142,6 +152,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantRoleErr: true,
|
wantRoleErr: true,
|
||||||
wantName: "computer-name",
|
wantName: "computer-name",
|
||||||
wantSubscriptionID: "subscription-id",
|
wantSubscriptionID: "subscription-id",
|
||||||
|
wantTags: map[string]string{cloud.TagUID: "uid"},
|
||||||
},
|
},
|
||||||
"metadata response without resource group": {
|
"metadata response without resource group": {
|
||||||
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutGroup),
|
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutGroup),
|
||||||
|
@ -151,6 +162,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantRole: role.Worker,
|
wantRole: role.Worker,
|
||||||
wantName: "computer-name",
|
wantName: "computer-name",
|
||||||
wantSubscriptionID: "subscription-id",
|
wantSubscriptionID: "subscription-id",
|
||||||
|
wantTags: defaultWantTags,
|
||||||
},
|
},
|
||||||
"metadata response without name": {
|
"metadata response without name": {
|
||||||
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutName),
|
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutName),
|
||||||
|
@ -160,6 +172,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantRole: role.Worker,
|
wantRole: role.Worker,
|
||||||
wantNameErr: true,
|
wantNameErr: true,
|
||||||
wantSubscriptionID: "subscription-id",
|
wantSubscriptionID: "subscription-id",
|
||||||
|
wantTags: defaultWantTags,
|
||||||
},
|
},
|
||||||
"metadata response without subscription ID": {
|
"metadata response without subscription ID": {
|
||||||
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutSubscriptionID),
|
server: newHTTPBufconnServerWithMetadataResponse(responseWithoutSubscriptionID),
|
||||||
|
@ -169,6 +182,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantRole: role.Worker,
|
wantRole: role.Worker,
|
||||||
wantName: "computer-name",
|
wantName: "computer-name",
|
||||||
wantSubscriptionErr: true,
|
wantSubscriptionErr: true,
|
||||||
|
wantTags: defaultWantTags,
|
||||||
},
|
},
|
||||||
"invalid imds response detected": {
|
"invalid imds response detected": {
|
||||||
server: newHTTPBufconnServer(func(writer http.ResponseWriter, request *http.Request) {
|
server: newHTTPBufconnServer(func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
@ -180,6 +194,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
wantRoleErr: true,
|
wantRoleErr: true,
|
||||||
wantNameErr: true,
|
wantNameErr: true,
|
||||||
wantSubscriptionErr: true,
|
wantSubscriptionErr: true,
|
||||||
|
wantTagsErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +212,7 @@ func TestIMDSClient(t *testing.T) {
|
||||||
DialTLS: tc.server.Dial,
|
DialTLS: tc.server.Dial,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
iClient := imdsClient{client: &hClient}
|
iClient := IMDSClient{client: &hClient}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
@ -248,6 +263,14 @@ func TestIMDSClient(t *testing.T) {
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(tc.wantSubscriptionID, subscriptionID)
|
assert.Equal(tc.wantSubscriptionID, subscriptionID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tags, err := iClient.Tags(ctx)
|
||||||
|
if tc.wantTagsErr {
|
||||||
|
assert.Error(err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(tc.wantTags, tags)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ func NewLogger(ctx context.Context) (*Logger, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("loading credentials: %w", err)
|
return nil, fmt.Errorf("loading credentials: %w", err)
|
||||||
}
|
}
|
||||||
imdsAPI := &imdsClient{
|
imdsAPI := &IMDSClient{
|
||||||
client: &http.Client{Transport: &http.Transport{Proxy: nil}},
|
client: &http.Client{Transport: &http.Transport{Proxy: nil}},
|
||||||
}
|
}
|
||||||
subscriptionID, err := imdsAPI.subscriptionID(ctx)
|
subscriptionID, err := imdsAPI.subscriptionID(ctx)
|
||||||
|
|
|
@ -192,7 +192,7 @@ type AzureConfig struct {
|
||||||
IDKeyDigest Digests `yaml:"idKeyDigest" validate:"required_if=EnforceIdKeyDigest true,omitempty"`
|
IDKeyDigest Digests `yaml:"idKeyDigest" validate:"required_if=EnforceIdKeyDigest true,omitempty"`
|
||||||
// description: |
|
// description: |
|
||||||
// Enforce the specified idKeyDigest value during remote attestation.
|
// Enforce the specified idKeyDigest value during remote attestation.
|
||||||
EnforceIDKeyDigest *bool `yaml:"enforceIdKeyDigest" validate:"required"`
|
EnforceIDKeyDigest idkeydigest.EnforceIDKeyDigest `yaml:"enforceIdKeyDigest" validate:"required"`
|
||||||
// description: |
|
// description: |
|
||||||
// Expected confidential VM measurements.
|
// Expected confidential VM measurements.
|
||||||
Measurements Measurements `yaml:"measurements" validate:"required,no_placeholders"`
|
Measurements Measurements `yaml:"measurements" validate:"required,no_placeholders"`
|
||||||
|
@ -329,7 +329,7 @@ func Default() *Config {
|
||||||
StateDiskType: "Premium_LRS",
|
StateDiskType: "Premium_LRS",
|
||||||
DeployCSIDriver: toPtr(true),
|
DeployCSIDriver: toPtr(true),
|
||||||
IDKeyDigest: idkeydigest.DefaultsFor(cloudprovider.Azure),
|
IDKeyDigest: idkeydigest.DefaultsFor(cloudprovider.Azure),
|
||||||
EnforceIDKeyDigest: toPtr(true),
|
EnforceIDKeyDigest: idkeydigest.MAAFallback,
|
||||||
ConfidentialVM: toPtr(true),
|
ConfidentialVM: toPtr(true),
|
||||||
SecureBoot: toPtr(false),
|
SecureBoot: toPtr(false),
|
||||||
Measurements: measurements.DefaultsFor(cloudprovider.Azure),
|
Measurements: measurements.DefaultsFor(cloudprovider.Azure),
|
||||||
|
@ -514,9 +514,12 @@ func (c *Config) GetMeasurements() measurements.M {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnforcesIDKeyDigest checks whether ID Key Digest should be enforced for respective cloud provider.
|
// IDKeyDigestPolicy returns the IDKeyDigest checking policy for a cloud provider.
|
||||||
func (c *Config) EnforcesIDKeyDigest() bool {
|
func (c *Config) IDKeyDigestPolicy() idkeydigest.EnforceIDKeyDigest {
|
||||||
return c.Provider.Azure != nil && c.Provider.Azure.EnforceIDKeyDigest != nil && *c.Provider.Azure.EnforceIDKeyDigest
|
if c.Provider.Azure != nil {
|
||||||
|
return c.Provider.Azure.EnforceIDKeyDigest
|
||||||
|
}
|
||||||
|
return idkeydigest.Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnforcedPCRs returns the list of enforced PCRs for the configured cloud provider.
|
// EnforcedPCRs returns the list of enforced PCRs for the configured cloud provider.
|
||||||
|
|
|
@ -265,7 +265,7 @@ func init() {
|
||||||
AzureConfigDoc.Fields[12].Description = "List of accepted values for the field 'idkeydigest' in the AMD SEV-SNP attestation report. Only usable with ConfidentialVMs. See 4.6 and 7.3 in: https://www.amd.com/system/files/TechDocs/56860.pdf"
|
AzureConfigDoc.Fields[12].Description = "List of accepted values for the field 'idkeydigest' in the AMD SEV-SNP attestation report. Only usable with ConfidentialVMs. See 4.6 and 7.3 in: https://www.amd.com/system/files/TechDocs/56860.pdf"
|
||||||
AzureConfigDoc.Fields[12].Comments[encoder.LineComment] = "List of accepted values for the field 'idkeydigest' in the AMD SEV-SNP attestation report. Only usable with ConfidentialVMs. See 4.6 and 7.3 in: https://www.amd.com/system/files/TechDocs/56860.pdf"
|
AzureConfigDoc.Fields[12].Comments[encoder.LineComment] = "List of accepted values for the field 'idkeydigest' in the AMD SEV-SNP attestation report. Only usable with ConfidentialVMs. See 4.6 and 7.3 in: https://www.amd.com/system/files/TechDocs/56860.pdf"
|
||||||
AzureConfigDoc.Fields[13].Name = "enforceIdKeyDigest"
|
AzureConfigDoc.Fields[13].Name = "enforceIdKeyDigest"
|
||||||
AzureConfigDoc.Fields[13].Type = "bool"
|
AzureConfigDoc.Fields[13].Type = "EnforceIDKeyDigest"
|
||||||
AzureConfigDoc.Fields[13].Note = ""
|
AzureConfigDoc.Fields[13].Note = ""
|
||||||
AzureConfigDoc.Fields[13].Description = "Enforce the specified idKeyDigest value during remote attestation."
|
AzureConfigDoc.Fields[13].Description = "Enforce the specified idKeyDigest value during remote attestation."
|
||||||
AzureConfigDoc.Fields[13].Comments[encoder.LineComment] = "Enforce the specified idKeyDigest value during remote attestation."
|
AzureConfigDoc.Fields[13].Comments[encoder.LineComment] = "Enforce the specified idKeyDigest value during remote attestation."
|
||||||
|
|
|
@ -740,7 +740,7 @@ func TestConfigVersionCompatibility(t *testing.T) {
|
||||||
ConfidentialVM: toPtr(true),
|
ConfidentialVM: toPtr(true),
|
||||||
InstanceType: "Standard_DC4as_v5",
|
InstanceType: "Standard_DC4as_v5",
|
||||||
IDKeyDigest: idkeydigest.IDKeyDigests{{0x03, 0x56, 0x21, 0x58, 0x82, 0xa8, 0x25, 0x27, 0x9a, 0x85, 0xb3, 0x00, 0xb0, 0xb7, 0x42, 0x93, 0x1d, 0x11, 0x3b, 0xf7, 0xe3, 0x2d, 0xde, 0x2e, 0x50, 0xff, 0xde, 0x7e, 0xc7, 0x43, 0xca, 0x49, 0x1e, 0xcd, 0xd7, 0xf3, 0x36, 0xdc, 0x28, 0xa6, 0xe0, 0xb2, 0xbb, 0x57, 0xaf, 0x7a, 0x44, 0xa3}},
|
IDKeyDigest: idkeydigest.IDKeyDigests{{0x03, 0x56, 0x21, 0x58, 0x82, 0xa8, 0x25, 0x27, 0x9a, 0x85, 0xb3, 0x00, 0xb0, 0xb7, 0x42, 0x93, 0x1d, 0x11, 0x3b, 0xf7, 0xe3, 0x2d, 0xde, 0x2e, 0x50, 0xff, 0xde, 0x7e, 0xc7, 0x43, 0xca, 0x49, 0x1e, 0xcd, 0xd7, 0xf3, 0x36, 0xdc, 0x28, 0xa6, 0xe0, 0xb2, 0xbb, 0x57, 0xaf, 0x7a, 0x44, 0xa3}},
|
||||||
EnforceIDKeyDigest: toPtr(false),
|
EnforceIDKeyDigest: idkeydigest.WarnOnly,
|
||||||
SecureBoot: toPtr(false),
|
SecureBoot: toPtr(false),
|
||||||
DeployCSIDriver: toPtr(true),
|
DeployCSIDriver: toPtr(true),
|
||||||
Measurements: measurements.DefaultsFor(cloudprovider.Azure),
|
Measurements: measurements.DefaultsFor(cloudprovider.Azure),
|
||||||
|
@ -772,7 +772,7 @@ func TestConfigVersionCompatibility(t *testing.T) {
|
||||||
{0x57, 0x48, 0x6a, 0x44, 0x7e, 0xc0, 0xf1, 0x95, 0x80, 0x02, 0xa2, 0x2a, 0x06, 0xb7, 0x67, 0x3b, 0x9f, 0xd2, 0x7d, 0x11, 0xe1, 0xc6, 0x52, 0x74, 0x98, 0x05, 0x60, 0x54, 0xc5, 0xfa, 0x92, 0xd2, 0x3c, 0x50, 0xf9, 0xde, 0x44, 0x07, 0x27, 0x60, 0xfe, 0x2b, 0x6f, 0xb8, 0x97, 0x40, 0xb6, 0x96},
|
{0x57, 0x48, 0x6a, 0x44, 0x7e, 0xc0, 0xf1, 0x95, 0x80, 0x02, 0xa2, 0x2a, 0x06, 0xb7, 0x67, 0x3b, 0x9f, 0xd2, 0x7d, 0x11, 0xe1, 0xc6, 0x52, 0x74, 0x98, 0x05, 0x60, 0x54, 0xc5, 0xfa, 0x92, 0xd2, 0x3c, 0x50, 0xf9, 0xde, 0x44, 0x07, 0x27, 0x60, 0xfe, 0x2b, 0x6f, 0xb8, 0x97, 0x40, 0xb6, 0x96},
|
||||||
{0x03, 0x56, 0x21, 0x58, 0x82, 0xa8, 0x25, 0x27, 0x9a, 0x85, 0xb3, 0x00, 0xb0, 0xb7, 0x42, 0x93, 0x1d, 0x11, 0x3b, 0xf7, 0xe3, 0x2d, 0xde, 0x2e, 0x50, 0xff, 0xde, 0x7e, 0xc7, 0x43, 0xca, 0x49, 0x1e, 0xcd, 0xd7, 0xf3, 0x36, 0xdc, 0x28, 0xa6, 0xe0, 0xb2, 0xbb, 0x57, 0xaf, 0x7a, 0x44, 0xa3},
|
{0x03, 0x56, 0x21, 0x58, 0x82, 0xa8, 0x25, 0x27, 0x9a, 0x85, 0xb3, 0x00, 0xb0, 0xb7, 0x42, 0x93, 0x1d, 0x11, 0x3b, 0xf7, 0xe3, 0x2d, 0xde, 0x2e, 0x50, 0xff, 0xde, 0x7e, 0xc7, 0x43, 0xca, 0x49, 0x1e, 0xcd, 0xd7, 0xf3, 0x36, 0xdc, 0x28, 0xa6, 0xe0, 0xb2, 0xbb, 0x57, 0xaf, 0x7a, 0x44, 0xa3},
|
||||||
},
|
},
|
||||||
EnforceIDKeyDigest: toPtr(false),
|
EnforceIDKeyDigest: idkeydigest.WarnOnly,
|
||||||
SecureBoot: toPtr(false),
|
SecureBoot: toPtr(false),
|
||||||
DeployCSIDriver: toPtr(true),
|
DeployCSIDriver: toPtr(true),
|
||||||
Measurements: measurements.DefaultsFor(cloudprovider.Azure),
|
Measurements: measurements.DefaultsFor(cloudprovider.Azure),
|
||||||
|
|
|
@ -116,6 +116,9 @@ const (
|
||||||
IDKeyDigestFilename = "idkeydigests"
|
IDKeyDigestFilename = "idkeydigests"
|
||||||
// EnforceIDKeyDigestFilename is the name of the file configuring whether idkeydigest is enforced or not.
|
// EnforceIDKeyDigestFilename is the name of the file configuring whether idkeydigest is enforced or not.
|
||||||
EnforceIDKeyDigestFilename = "enforceIdKeyDigest"
|
EnforceIDKeyDigestFilename = "enforceIdKeyDigest"
|
||||||
|
// IDKeyConfigFilename is the name of the file holding the configuration for validating the SEV-SNP ID key digest.
|
||||||
|
IDKeyConfigFilename = "idKeyConfig"
|
||||||
|
|
||||||
// K8sVersionFieldName is the name of the of the key holding the wanted Kubernetes version.
|
// K8sVersionFieldName is the name of the of the key holding the wanted Kubernetes version.
|
||||||
K8sVersionFieldName = "cluster-version"
|
K8sVersionFieldName = "cluster-version"
|
||||||
// ComponentsListKey is the name of the key holding the list of components in the components configMap.
|
// ComponentsListKey is the name of the key holding the list of components in the components configMap.
|
||||||
|
|
|
@ -19,6 +19,7 @@ go_library(
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
"//internal/oid",
|
"//internal/oid",
|
||||||
"@com_github_fsnotify_fsnotify//:fsnotify",
|
"@com_github_fsnotify_fsnotify//:fsnotify",
|
||||||
|
"@com_github_spf13_afero//:afero",
|
||||||
"@org_uber_go_zap//:zap",
|
"@org_uber_go_zap//:zap",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,9 +9,9 @@ package watcher
|
||||||
import (
|
import (
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||||
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/oid"
|
"github.com/edgelesssys/constellation/v2/internal/oid"
|
||||||
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Updatable implements an updatable atls.Validator.
|
// Updatable implements an updatable atls.Validator.
|
||||||
|
@ -74,21 +75,32 @@ func (u *Updatable) Update() error {
|
||||||
}
|
}
|
||||||
u.log.Debugf("New measurements: %+v", measurements)
|
u.log.Debugf("New measurements: %+v", measurements)
|
||||||
|
|
||||||
var digest idkeydigest.IDKeyDigests
|
// Read ID Key config
|
||||||
var enforceIDKeyDigest bool
|
var idKeyCfg idkeydigest.Config
|
||||||
if u.variant.OID().Equal(oid.AzureSEVSNP{}.OID()) {
|
if u.variant.OID().Equal(oid.AzureSEVSNP{}.OID()) {
|
||||||
u.log.Infof("Updating encforceIdKeyDigest value")
|
u.log.Infof("Updating SEV-SNP ID Key config")
|
||||||
|
|
||||||
|
err := u.fileHandler.ReadJSON(filepath.Join(constants.ServiceBasePath, constants.IDKeyConfigFilename), &idKeyCfg)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, afero.ErrFileNotFound) {
|
||||||
|
return fmt.Errorf("reading ID Key config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
u.log.Warnf("ID Key config file not found, falling back to old format (v2.6 or earlier)")
|
||||||
|
|
||||||
|
// v2.6 fallback
|
||||||
|
// TODO: Remove after v2.7 release
|
||||||
|
var digest idkeydigest.IDKeyDigests
|
||||||
|
var enforceIDKeyDigest idkeydigest.EnforceIDKeyDigest
|
||||||
enforceRaw, err := u.fileHandler.Read(filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename))
|
enforceRaw, err := u.fileHandler.Read(filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
enforceIDKeyDigest, err = strconv.ParseBool(string(enforceRaw))
|
enforceIDKeyDigest = idkeydigest.EnforcePolicyFromString(string(enforceRaw))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parsing content of EnforceIdKeyDigestFilename: %s: %w", enforceRaw, err)
|
return fmt.Errorf("parsing content of EnforceIdKeyDigestFilename: %s: %w", enforceRaw, err)
|
||||||
}
|
}
|
||||||
u.log.Debugf("New encforceIdKeyDigest value: %v", enforceIDKeyDigest)
|
|
||||||
|
|
||||||
u.log.Infof("Updating expected idkeydigest")
|
|
||||||
idkeydigestRaw, err := u.fileHandler.Read(filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename))
|
idkeydigestRaw, err := u.fileHandler.Read(filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -96,10 +108,15 @@ func (u *Updatable) Update() error {
|
||||||
if err = json.Unmarshal(idkeydigestRaw, &digest); err != nil {
|
if err = json.Unmarshal(idkeydigestRaw, &digest); err != nil {
|
||||||
return fmt.Errorf("unmarshaling content of IDKeyDigestFilename: %s: %w", idkeydigestRaw, err)
|
return fmt.Errorf("unmarshaling content of IDKeyDigestFilename: %s: %w", idkeydigestRaw, err)
|
||||||
}
|
}
|
||||||
u.log.Debugf("New idkeydigest: %v", digest)
|
|
||||||
|
idKeyCfg.IDKeyDigests = digest
|
||||||
|
idKeyCfg.EnforcementPolicy = enforceIDKeyDigest
|
||||||
}
|
}
|
||||||
|
|
||||||
validator, err := choose.Validator(u.variant, measurements, digest, enforceIDKeyDigest, u.log)
|
u.log.Debugf("New ID Key config: %+v", idKeyCfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
validator, err := choose.Validator(u.variant, measurements, idKeyCfg, u.log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("updating validator: %w", err)
|
return fmt.Errorf("updating validator: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,15 +79,13 @@ func TestNewUpdateableValidator(t *testing.T) {
|
||||||
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
||||||
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
||||||
))
|
))
|
||||||
keyDigest, err := json.Marshal(idkeydigest.DefaultsFor(cloudprovider.Azure))
|
|
||||||
require.NoError(err)
|
require.NoError(handler.WriteJSON(
|
||||||
require.NoError(handler.Write(
|
filepath.Join(constants.ServiceBasePath, constants.IDKeyConfigFilename),
|
||||||
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
idkeydigest.Config{
|
||||||
keyDigest,
|
IDKeyDigests: idkeydigest.DefaultsFor(cloudprovider.Azure),
|
||||||
))
|
EnforcementPolicy: idkeydigest.WarnOnly,
|
||||||
require.NoError(handler.Write(
|
},
|
||||||
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
|
||||||
[]byte("false"),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,13 +124,12 @@ func TestUpdate(t *testing.T) {
|
||||||
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
||||||
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
||||||
))
|
))
|
||||||
require.NoError(handler.Write(
|
require.NoError(handler.WriteJSON(
|
||||||
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
filepath.Join(constants.ServiceBasePath, constants.IDKeyConfigFilename),
|
||||||
[]byte{},
|
idkeydigest.Config{
|
||||||
))
|
IDKeyDigests: idkeydigest.IDKeyDigests{[]byte{0x00}},
|
||||||
require.NoError(handler.Write(
|
EnforcementPolicy: idkeydigest.WarnOnly,
|
||||||
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
},
|
||||||
[]byte("false"),
|
|
||||||
))
|
))
|
||||||
|
|
||||||
// call update once to initialize the server's validator
|
// call update once to initialize the server's validator
|
||||||
|
@ -167,6 +164,18 @@ func TestUpdate(t *testing.T) {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
}
|
}
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
|
||||||
|
// test old ID Key Digest format
|
||||||
|
require.NoError(handler.Write(
|
||||||
|
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
||||||
|
[]byte{},
|
||||||
|
))
|
||||||
|
require.NoError(handler.Write(
|
||||||
|
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
||||||
|
[]byte("false"),
|
||||||
|
))
|
||||||
|
|
||||||
|
assert.NoError(validator.Update())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOIDConcurrency(t *testing.T) {
|
func TestOIDConcurrency(t *testing.T) {
|
||||||
|
@ -178,9 +187,12 @@ func TestOIDConcurrency(t *testing.T) {
|
||||||
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
filepath.Join(constants.ServiceBasePath, constants.MeasurementsFilename),
|
||||||
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
||||||
))
|
))
|
||||||
require.NoError(handler.Write(
|
require.NoError(handler.WriteJSON(
|
||||||
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
filepath.Join(constants.ServiceBasePath, constants.IDKeyConfigFilename),
|
||||||
[]byte{},
|
idkeydigest.Config{
|
||||||
|
IDKeyDigests: idkeydigest.IDKeyDigests{[]byte{0x00}},
|
||||||
|
EnforcementPolicy: idkeydigest.WarnOnly,
|
||||||
|
},
|
||||||
))
|
))
|
||||||
|
|
||||||
// create server
|
// create server
|
||||||
|
@ -223,13 +235,12 @@ func TestUpdateConcurrency(t *testing.T) {
|
||||||
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
measurements.M{11: measurements.WithAllBytes(0x00, false)},
|
||||||
file.OptNone,
|
file.OptNone,
|
||||||
))
|
))
|
||||||
require.NoError(handler.Write(
|
require.NoError(handler.WriteJSON(
|
||||||
filepath.Join(constants.ServiceBasePath, constants.IDKeyDigestFilename),
|
filepath.Join(constants.ServiceBasePath, constants.IDKeyConfigFilename),
|
||||||
[]byte{},
|
idkeydigest.Config{
|
||||||
))
|
IDKeyDigests: idkeydigest.IDKeyDigests{[]byte{0x00}},
|
||||||
require.NoError(handler.Write(
|
EnforcementPolicy: idkeydigest.WarnOnly,
|
||||||
filepath.Join(constants.ServiceBasePath, constants.EnforceIDKeyDigestFilename),
|
},
|
||||||
[]byte("false"),
|
|
||||||
))
|
))
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue