mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-22 20:00:18 +00:00
NOISSUE - Track TDX policy (#557)
* Add initial implementation of attestation policy for SEV-SNP and TDX, including JSON configuration files and build scripts Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Update working directory for Rust CI pipeline to sev-snp Signed-off-by: Sammy Oina <sammyoina@gmail.com> * fix build Signed-off-by: Sammy Oina <sammyoina@gmail.com> * fix tests Signed-off-by: Sammy Oina <sammyoina@gmail.com> * fix tests Signed-off-by: Sammy Oina <sammyoina@gmail.com> --------- Signed-off-by: Sammy Oina <sammyoina@gmail.com>
This commit is contained in:
committed by
GitHub
parent
c422afe0a6
commit
3498db14fb
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./scripts/attestation_policy
|
||||
working-directory: ./scripts/attestation_policy/sev-snp
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
|
||||
@@ -50,6 +50,7 @@ install: $(SERVICES) $(ATTESTATION_POLICY)
|
||||
install $(BUILD_DIR)/cocos-cli $(INSTALL_DIR)/cocos-cli
|
||||
install $(BUILD_DIR)/cocos-manager $(INSTALL_DIR)/cocos-manager
|
||||
install $(BUILD_DIR)/attestation_policy $(INSTALL_DIR)/attestation_policy
|
||||
install $(BUILD_DIR)/attestation_policy_tdx $(INSTALL_DIR)/attestation_policy_tdx
|
||||
install -d $(CONFIG_DIR)
|
||||
install cocos-manager.env $(CONFIG_DIR)/cocos-manager.env
|
||||
|
||||
|
||||
@@ -301,6 +301,52 @@ func (cli *CLI) NewAzureAttestationPolicy() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (cli *CLI) NewTDXAttestationPolicy() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "tdx",
|
||||
Short: "Get attestation policy for TDX CVM",
|
||||
Example: `tdx <tdx_attestation_report_file>`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
attestationFile := args[0]
|
||||
|
||||
// Parse TDX configuration from flags or config file
|
||||
if err := validateTDXFlags(); err != nil {
|
||||
printError(cmd, "Error validating TDX flags: %v ❌ ", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Read and verify the attestation report to extract policy values
|
||||
attestationBytes, err := os.ReadFile(attestationFile)
|
||||
if err != nil {
|
||||
printError(cmd, "Error reading attestation report file: %v ❌ ", err)
|
||||
return
|
||||
}
|
||||
|
||||
// If the config is not provided via flags, we can extract it from the attestation report
|
||||
// For now, we'll use the cfgTDX that was populated from flags
|
||||
if len(attestationBytes) > 0 {
|
||||
cmd.Printf("Read %d bytes from attestation report\n", len(attestationBytes))
|
||||
}
|
||||
|
||||
attestationPolicyJson, err := json.MarshalIndent(cfgTDX, "", " ")
|
||||
if err != nil {
|
||||
printError(cmd, "Error marshaling attestation policy: %v ❌ ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.WriteFile("attestation_policy.json", attestationPolicyJson, filePermission); err != nil {
|
||||
printError(cmd, "Error writing attestation policy file: %v ❌ ", err)
|
||||
return
|
||||
}
|
||||
|
||||
cmd.Println("Attestation policy file generated successfully ✅")
|
||||
},
|
||||
}
|
||||
|
||||
return addTDXVerificationOptions(cmd)
|
||||
}
|
||||
|
||||
func (cli *CLI) NewExtendWithManifestCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "extend",
|
||||
|
||||
@@ -397,7 +397,7 @@ func TestExtendWithManifestHandling(t *testing.T) {
|
||||
|
||||
t.Run("Invalid manifest file", func(t *testing.T) {
|
||||
cmd := cli.NewExtendWithManifestCmd()
|
||||
cmd.SetArgs([]string{"../scripts/attestation_policy/attestation_policy.json", "nonexistent.manifest.json"})
|
||||
cmd.SetArgs([]string{"../scripts/attestation_policy/sev-snp/attestation_policy.json", "nonexistent.manifest.json"})
|
||||
|
||||
var buf bytes.Buffer
|
||||
cmd.SetOut(&buf)
|
||||
@@ -458,7 +458,7 @@ func TestExtendWithManifestHandling(t *testing.T) {
|
||||
}
|
||||
|
||||
cmd := cli.NewExtendWithManifestCmd()
|
||||
cmd.SetArgs([]string{"../scripts/attestation_policy/attestation_policy.json", manifestFile.Name()})
|
||||
cmd.SetArgs([]string{"../scripts/attestation_policy/sev-snp/attestation_policy.json", manifestFile.Name()})
|
||||
|
||||
var buf bytes.Buffer
|
||||
cmd.SetOut(&buf)
|
||||
|
||||
@@ -164,6 +164,7 @@ func main() {
|
||||
attestationPolicyCmd.AddCommand(cliSVC.NewGCPAttestationPolicy())
|
||||
attestationPolicyCmd.AddCommand(cliSVC.NewDownloadGCPOvmfFile())
|
||||
attestationPolicyCmd.AddCommand(cliSVC.NewAzureAttestationPolicy())
|
||||
attestationPolicyCmd.AddCommand(cliSVC.NewTDXAttestationPolicy())
|
||||
attestationPolicyCmd.AddCommand(cliSVC.NewExtendWithManifestCmd())
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
|
||||
@@ -596,7 +596,7 @@ func prepVerifyAttReport(t *testing.T) *sevsnp.Attestation {
|
||||
}
|
||||
|
||||
func setAttestationPolicy(rr *sevsnp.Attestation, policyDirectory string) error {
|
||||
attestationPolicyFile, err := os.ReadFile("../../scripts/attestation_policy/attestation_policy.json")
|
||||
attestationPolicyFile, err := os.ReadFile("../../scripts/attestation_policy/sev-snp/attestation_policy.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -807,7 +807,7 @@ func prepVerifyAttReport(t *testing.T) (*sevsnp.Attestation, []byte) {
|
||||
}
|
||||
|
||||
func setAttestationPolicy(rr *sevsnp.Attestation, policyDirectory string) error {
|
||||
attestationPolicyFile, err := os.ReadFile("../../../scripts/attestation_policy/attestation_policy.json")
|
||||
attestationPolicyFile, err := os.ReadFile("../../../scripts/attestation_policy/sev-snp/attestation_policy.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestNewClient(t *testing.T) {
|
||||
ClientKey: clientKeyFile,
|
||||
},
|
||||
AttestedTLS: true,
|
||||
AttestationPolicy: "../../../scripts/attestation_policy/attestation_policy.json",
|
||||
AttestationPolicy: "../../../scripts/attestation_policy/sev-snp/attestation_policy.json",
|
||||
},
|
||||
wantErr: false,
|
||||
err: nil,
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
CARGO = cargo
|
||||
TARGET = target
|
||||
BUILD_DIR = $(TARGET)/release
|
||||
BIN_NAME = attestation_policy
|
||||
OUTPUT_DIR ?= $(BUILD_DIR)
|
||||
OUTPUT_DIR ?= ../../build
|
||||
PLATFORMS = sev-snp tdx
|
||||
# Convert OUTPUT_DIR to absolute path
|
||||
ABS_OUTPUT_DIR := $(shell cd $(OUTPUT_DIR) 2>/dev/null && pwd || mkdir -p $(OUTPUT_DIR) && cd $(OUTPUT_DIR) && pwd)
|
||||
|
||||
all: build
|
||||
.PHONY: all build clean $(PLATFORMS)
|
||||
|
||||
build:
|
||||
$(CARGO) build --release
|
||||
@if [ "$(OUTPUT_DIR)" != "$(BUILD_DIR)" ]; then \
|
||||
mkdir -p $(OUTPUT_DIR) && \
|
||||
cp $(BUILD_DIR)/$(BIN_NAME) $(OUTPUT_DIR)/$(BIN_NAME) && \
|
||||
echo "Copied $(BIN_NAME) to $(OUTPUT_DIR)/"; \
|
||||
fi
|
||||
all: $(PLATFORMS)
|
||||
|
||||
$(PLATFORMS):
|
||||
$(MAKE) -C $@ OUTPUT_DIR=$(ABS_OUTPUT_DIR)
|
||||
|
||||
clean:
|
||||
$(CARGO) clean
|
||||
@if [ "$(OUTPUT_DIR)" != "$(BUILD_DIR)" ] && [ -f "$(OUTPUT_DIR)/$(BIN_NAME)" ]; then \
|
||||
rm -f $(OUTPUT_DIR)/$(BIN_NAME) && \
|
||||
echo "Removed $(BIN_NAME) from $(OUTPUT_DIR)/"; \
|
||||
fi
|
||||
|
||||
.PHONY: all build clean
|
||||
@for platform in $(PLATFORMS); do \
|
||||
$(MAKE) -C $$platform OUTPUT_DIR=$(ABS_OUTPUT_DIR) clean; \
|
||||
done
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
CARGO = cargo
|
||||
TARGET = target
|
||||
BUILD_DIR = $(TARGET)/release
|
||||
BIN_NAME = attestation_policy
|
||||
OUTPUT_DIR ?= $(BUILD_DIR)
|
||||
|
||||
all: build
|
||||
|
||||
build:
|
||||
$(CARGO) build --release
|
||||
@if [ "$(OUTPUT_DIR)" != "$(BUILD_DIR)" ]; then \
|
||||
mkdir -p $(OUTPUT_DIR) && \
|
||||
cp $(BUILD_DIR)/$(BIN_NAME) $(OUTPUT_DIR)/$(BIN_NAME) && \
|
||||
echo "Copied $(BIN_NAME) to $(OUTPUT_DIR)/"; \
|
||||
fi
|
||||
|
||||
clean:
|
||||
$(CARGO) clean
|
||||
@if [ "$(OUTPUT_DIR)" != "$(BUILD_DIR)" ] && [ -f "$(OUTPUT_DIR)/$(BIN_NAME)" ]; then \
|
||||
rm -f $(OUTPUT_DIR)/$(BIN_NAME) && \
|
||||
echo "Removed $(BIN_NAME) from $(OUTPUT_DIR)/"; \
|
||||
fi
|
||||
|
||||
.PHONY: all build clean
|
||||
@@ -0,0 +1,27 @@
|
||||
GO = go
|
||||
TARGET = target
|
||||
BUILD_DIR = .
|
||||
BIN_NAME = attestation_policy_tdx
|
||||
OUTPUT_DIR ?= $(BUILD_DIR)
|
||||
|
||||
all: build
|
||||
|
||||
build:
|
||||
$(GO) build -o $(BUILD_DIR)/$(BIN_NAME) .
|
||||
@if [ "$(OUTPUT_DIR)" != "$(BUILD_DIR)" ]; then \
|
||||
mkdir -p $(OUTPUT_DIR) && \
|
||||
cp $(BUILD_DIR)/$(BIN_NAME) $(OUTPUT_DIR)/$(BIN_NAME) && \
|
||||
echo "Copied $(BIN_NAME) to $(OUTPUT_DIR)/"; \
|
||||
fi
|
||||
|
||||
clean:
|
||||
@if [ -f "$(BUILD_DIR)/$(BIN_NAME)" ]; then \
|
||||
rm -f $(BUILD_DIR)/$(BIN_NAME) && \
|
||||
echo "Removed $(BIN_NAME) from $(BUILD_DIR)/"; \
|
||||
fi
|
||||
@if [ "$(OUTPUT_DIR)" != "$(BUILD_DIR)" ] && [ -f "$(OUTPUT_DIR)/$(BIN_NAME)" ]; then \
|
||||
rm -f $(OUTPUT_DIR)/$(BIN_NAME) && \
|
||||
echo "Removed $(BIN_NAME) from $(OUTPUT_DIR)/"; \
|
||||
fi
|
||||
|
||||
.PHONY: all build clean
|
||||
@@ -0,0 +1,7 @@
|
||||
module tdxpolicy
|
||||
|
||||
go 1.24.2
|
||||
|
||||
require github.com/google/go-tdx-guest v0.3.1
|
||||
|
||||
require google.golang.org/protobuf v1.36.10
|
||||
@@ -0,0 +1,6 @@
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-tdx-guest v0.3.1 h1:gl0KvjdsD4RrJzyLefDOvFOUH3NAJri/3qvaL5m83Iw=
|
||||
github.com/google/go-tdx-guest v0.3.1/go.mod h1:/rc3d7rnPykOPuY8U9saMyEps0PZDThLk/RygXm04nE=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"os"
|
||||
|
||||
ccpb "github.com/google/go-tdx-guest/proto/checkconfig"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
|
||||
var (
|
||||
SGXVendorID = []byte{0x93, 0x9A, 0x72, 0x33, 0xF7, 0x9C, 0x4C, 0xA9, 0x94, 0x0A, 0x0D, 0xB3, 0x95, 0x7F, 0x06, 0x07}
|
||||
MinTdxSvn = []byte{0x06, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
MrSeam = "5b38e33a6487958b72c3c12a938eaa5e3fd4510c51aeeab58c7d5ecee41d7c436489d6c8e4f92f160b7cad34207b00c1"
|
||||
TdAttributes = []byte{
|
||||
0x00, 0x00, 0x00, 0x10,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
Xfam = []byte{
|
||||
0xe7, 0x02, 0x06, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
MrTd = []byte{
|
||||
0x91, 0xeb, 0x2b, 0x44, 0xd1, 0x41, 0xd4, 0xec,
|
||||
0xe0, 0x9f, 0x0c, 0x75, 0xc2, 0xc5, 0x3d, 0x24,
|
||||
0x7a, 0x3c, 0x68, 0xed, 0xd7, 0xfa, 0xfe, 0x8a,
|
||||
0x35, 0x20, 0xc9, 0x42, 0xa6, 0x04, 0xa4, 0x07,
|
||||
0xde, 0x03, 0xae, 0x6d, 0xc5, 0xf8, 0x7f, 0x27,
|
||||
0x42, 0x8b, 0x25, 0x38, 0x87, 0x31, 0x18, 0xb7,
|
||||
}
|
||||
rtmr = []string{
|
||||
"ce0891f46a18db93e7691f1cf73ed76593f7dec1b58f0927ccb56a99242bf63bc9551561f9ee7833d40395fae59547ab",
|
||||
"062ac322e26b10874a84977a09735408a856aec77ff62b4975b1e90e33c18f05220ea522cdbffc3b2cf4451cc209e418",
|
||||
"5fd86e8c3d5e45386f1ed0852de7e83ae1b774ee4366bd5213c9890e8e3ac8fad3f7e690891d37f7c81ac20a445cc0ff",
|
||||
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfgTdx := &ccpb.Config{
|
||||
RootOfTrust: &ccpb.RootOfTrust{},
|
||||
Policy: &ccpb.Policy{HeaderPolicy: &ccpb.HeaderPolicy{}, TdQuoteBodyPolicy: &ccpb.TDQuoteBodyPolicy{}},
|
||||
}
|
||||
|
||||
cfgTdx.RootOfTrust.CheckCrl = true
|
||||
cfgTdx.RootOfTrust.GetCollateral = true
|
||||
|
||||
cfgTdx.Policy.HeaderPolicy.QeVendorId = SGXVendorID
|
||||
cfgTdx.Policy.TdQuoteBodyPolicy.MinimumTeeTcbSvn = MinTdxSvn
|
||||
|
||||
seam, err := hex.DecodeString(MrSeam)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cfgTdx.Policy.TdQuoteBodyPolicy.MrSeam = seam
|
||||
cfgTdx.Policy.TdQuoteBodyPolicy.TdAttributes = TdAttributes
|
||||
cfgTdx.Policy.TdQuoteBodyPolicy.Xfam = Xfam
|
||||
cfgTdx.Policy.TdQuoteBodyPolicy.MrTd = MrTd
|
||||
|
||||
for _, reg := range rtmr {
|
||||
r, err := hex.DecodeString(reg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cfgTdx.Policy.TdQuoteBodyPolicy.Rtmrs = append(cfgTdx.Policy.TdQuoteBodyPolicy.Rtmrs, r)
|
||||
}
|
||||
marshaler := protojson.MarshalOptions{
|
||||
Multiline: true,
|
||||
Indent: " ",
|
||||
}
|
||||
tdxPolicy, err := marshaler.Marshal(cfgTdx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = os.WriteFile("tdx_policy.json", tdxPolicy, 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = os.Stdout.Write(tdxPolicy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Policy := &ccpb.Config{
|
||||
RootOfTrust: &ccpb.RootOfTrust{},
|
||||
Policy: &ccpb.Policy{HeaderPolicy: &ccpb.HeaderPolicy{}, TdQuoteBodyPolicy: &ccpb.TDQuoteBodyPolicy{}},
|
||||
}
|
||||
|
||||
if err := ReadTDXAttestationPolicy("/home/cocosai/work/test/tdxpolicy/tdx_policy.json", Policy); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ReadTDXAttestationPolicy(policyPath string, policy *ccpb.Config) error {
|
||||
policyByte, err := os.ReadFile(policyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := protojson.Unmarshal(policyByte, policy); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// fmt.Print("Read TDX Attestation Policy:\n")
|
||||
// fmt.Printf(policy.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -64,7 +64,7 @@ cd ../..
|
||||
./build/cocos-cli policy hostdata '<host-data>' '<attestation_policy.json>'
|
||||
|
||||
# For attested TLS, also define the path to the attestation_policy.json that contains reference values for the fields of the attestation report
|
||||
export AGENT_GRPC_ATTESTATION_POLICY=./scripts/attestation_policy/attestation_policy.json
|
||||
export AGENT_GRPC_ATTESTATION_POLICY=./scripts/attestation_policy/sev-snp/attestation_policy.json
|
||||
export AGENT_GRPC_ATTESTED_TLS=true
|
||||
|
||||
# Retrieve Attestation
|
||||
|
||||
Reference in New Issue
Block a user