Skip to content

Commit

Permalink
initdata: use annotation to provision config files
Browse files Browse the repository at this point in the history
Fixes: #1895

Signed-off-by: Qi Feng Huo <[email protected]>
  • Loading branch information
Qi Feng Huo committed Aug 6, 2024
1 parent 09c6c83 commit b4f8b98
Show file tree
Hide file tree
Showing 10 changed files with 481 additions and 164 deletions.
15 changes: 1 addition & 14 deletions src/cloud-api-adaptor/cmd/process-user-data/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import (
"os"

cmdUtil "github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/cmd"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/aa"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/agent"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/cdh"
daemon "github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/forwarder"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/userdata"
"github.com/spf13/cobra"
)
Expand All @@ -19,9 +15,6 @@ const (
programName = "process-user-data"
providerAzure = "azure"
providerAws = "aws"

defaultAuthJsonPath = "/run/peerpod/auth.json"
defaultAgentConfigPath = "/run/peerpod/agent-config.toml"
)

var versionFlag bool
Expand All @@ -38,20 +31,14 @@ var rootCmd = &cobra.Command{
}

func init() {
var aaConfigPath, agentConfigPath, cdhConfigPath, daemonConfigPath string
var fetchTimeout int

rootCmd.PersistentFlags().BoolVarP(&versionFlag, "version", "v", false, "Print the version")
rootCmd.PersistentFlags().StringVarP(&daemonConfigPath, "daemon-config-path", "d", daemon.DefaultConfigPath, "Path to a daemon config file")
rootCmd.PersistentFlags().StringVarP(&aaConfigPath, "aa-config-path", "a", aa.DefaultAaConfigPath, "Path to a AA config file")
rootCmd.PersistentFlags().StringVarP(&agentConfigPath, "agent-config-path", "k", agent.ConfigFilePath, "Path to a kata agent config file")
rootCmd.PersistentFlags().StringVarP(&cdhConfigPath, "cdh-config-path", "c", cdh.ConfigFilePath, "Path to a CDH config file")

var provisionFilesCmd = &cobra.Command{
Use: "provision-files",
Short: "Provision required files based on user data",
RunE: func(_ *cobra.Command, _ []string) error {
cfg := userdata.NewConfig(aaConfigPath, agentConfigPath, defaultAuthJsonPath, daemonConfigPath, cdhConfigPath, fetchTimeout)
cfg := userdata.NewConfig(fetchTimeout)
return userdata.ProvisionFiles(cfg)
},
SilenceUsage: true, // Silence usage on error
Expand Down
111 changes: 111 additions & 0 deletions src/cloud-api-adaptor/docs/initdata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Initdata

The document describes the implementation of the [initdata](https://github.com/confidential-containers/trustee/blob/main/kbs/docs/initdata.md) spec in PeerPods.

## Initdata example

[attestation-agent](https://github.com/confidential-containers/guest-components/tree/main/attestation-agent) config file `aa.toml`, [confidential-data-hub](https://github.com/confidential-containers/guest-components/tree/main/confidential-data-hub) config file `cdh.toml` and a lightweight policy file `polciy.rego` can be passed into PeerPod via initdata.

Example:
```toml
algorithm = "sha384"
version = "0.1.0"

[data]
"aa.toml" = '''
[token_configs]
[token_configs.coco_as]
url = 'http://127.0.0.1:8080'
[token_configs.kbs]
url = 'http://127.0.0.1:8080'
'''

"cdh.toml" = '''
socket = 'unix:///run/confidential-containers/cdh.sock'
credentials = []
[kbc]
name = 'cc_kbc'
url = 'http://1.2.3.4:8080'
'''

"policy.rego" = '''
package agent_policy
import future.keywords.in
import future.keywords.every
import input
# Default values, returned by OPA when rules cannot be evaluated to true.
default CopyFileRequest := false
default CreateContainerRequest := false
default CreateSandboxRequest := true
default DestroySandboxRequest := true
default ExecProcessRequest := false
default GetOOMEventRequest := true
default GuestDetailsRequest := true
default OnlineCPUMemRequest := true
default PullImageRequest := true
default ReadStreamRequest := false
default RemoveContainerRequest := true
default RemoveStaleVirtiofsShareMountsRequest := true
default SignalProcessRequest := true
default StartContainerRequest := true
default StatsContainerRequest := true
default TtyWinResizeRequest := true
default UpdateEphemeralMountsRequest := true
default UpdateInterfaceRequest := true
default UpdateRoutesRequest := true
default WaitProcessRequest := true
default WriteStreamRequest := false
'''
```

## Annotation in Pod yaml
Generate base64 encoded string based on above example and pass it into PeerPod via annotation `io.katacontainers.config.runtime.cc_init_data`:
```yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: busybox
name: busybox
annotations:
io.katacontainers.config.runtime.cc_init_data: YWxnb3JpdGhtID0gInNoYTM4NCIKdmVyc2lvbiA9ICIwLjEuMCIKCltkYXRhXQoiYWEudG9tbCIgPSAnJycKW3Rva2VuX2NvbmZpZ3NdClt0b2tlbl9jb25maWdzLmNvY29fYXNdCnVybCA9ICdodHRwOi8vMTI3LjAuMC4xOjgwODAnCgpbdG9rZW5fY29uZmlncy5rYnNdCnVybCA9ICdodHRwOi8vMTI3LjAuMC4xOjgwODAnCicnJwoKImNkaC50b21sIiAgPSAnJycKc29ja2V0ID0gJ3VuaXg6Ly8vcnVuL2NvbmZpZGVudGlhbC1jb250YWluZXJzL2NkaC5zb2NrJwpjcmVkZW50aWFscyA9IFtdCgpba2JjXQpuYW1lID0gJ2NjX2tiYycKdXJsID0gJ2h0dHA6Ly8xLjIuMy40OjgwODAnCicnJwoKInBvbGljeS5yZWdvIiA9ICcnJwpwYWNrYWdlIGFnZW50X3BvbGljeQoKaW1wb3J0IGZ1dHVyZS5rZXl3b3Jkcy5pbgppbXBvcnQgZnV0dXJlLmtleXdvcmRzLmV2ZXJ5CgppbXBvcnQgaW5wdXQKCiMgRGVmYXVsdCB2YWx1ZXMsIHJldHVybmVkIGJ5IE9QQSB3aGVuIHJ1bGVzIGNhbm5vdCBiZSBldmFsdWF0ZWQgdG8gdHJ1ZS4KZGVmYXVsdCBDb3B5RmlsZVJlcXVlc3QgOj0gZmFsc2UKZGVmYXVsdCBDcmVhdGVDb250YWluZXJSZXF1ZXN0IDo9IGZhbHNlCmRlZmF1bHQgQ3JlYXRlU2FuZGJveFJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IERlc3Ryb3lTYW5kYm94UmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgRXhlY1Byb2Nlc3NSZXF1ZXN0IDo9IGZhbHNlCmRlZmF1bHQgR2V0T09NRXZlbnRSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBHdWVzdERldGFpbHNSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBPbmxpbmVDUFVNZW1SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBQdWxsSW1hZ2VSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZWFkU3RyZWFtUmVxdWVzdCA6PSBmYWxzZQpkZWZhdWx0IFJlbW92ZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFJlbW92ZVN0YWxlVmlydGlvZnNTaGFyZU1vdW50c1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFNpZ25hbFByb2Nlc3NSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBTdGFydENvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFN0YXRzQ29udGFpbmVyUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgVHR5V2luUmVzaXplUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgVXBkYXRlRXBoZW1lcmFsTW91bnRzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgVXBkYXRlSW50ZXJmYWNlUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgVXBkYXRlUm91dGVzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgV2FpdFByb2Nlc3NSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBXcml0ZVN0cmVhbVJlcXVlc3QgOj0gZmFsc2UKJycn
spec:
containers:
- image: quay.io/prometheus/busybox
name: busybox
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Never
runtimeClassName: kata-remote
```
## Structure in `write_files`
cloud-api-adaptor will read the annotation and write it to [write_files](../../cloud-providers/util/cloudinit/cloudconfig.go). Note: files unrelated to initdata (like network tunnel configuration in `/run/peerpod/daemon.json`) are also part of the `write_files` directive.
```yaml
write_files:
- path: /run/peerpod/agent-config.toml
content:
- path: /run/peerpod/daemon.json
content:
- path: /run/peerpod/auth.json
content:
- path: /run/peerpod/initdata
content:
```

## Provision initdata files.
`/run/peerpod/aa.toml`, `/run/peerpod/cdh.toml` and `/run/peerpod/policy.rego` will be provisioned from `/run/peerpod/initdata` via [process-user-data](../cmd/process-user-data/main.go).

It also calculates the digest `/run/peerpod/initdata.digest` based on the `algorithm` in `/run/peerpod/initdata` and its contents.

`/run/peerpod/initdata.digest` could be used by the TEE drivers.

The digest can be calculated manually and set to attestation service policy before hand if needed. To calculate the digest, use a tool (for example some online sha tools) to calculate the hash value based on the initdata annotation string. The calculated sha384 is: `14980c75860de9adcba2e0e494fc612f0f4fe3d86f5dc8e238a3255acfdf43bf82b9ccfc21da95d639ff0c98cc15e05e` for above sample.

## TODO
A large policy bodies that cannot be provisioned via IMDS user-data, the limitation depends on providers IMDS limitation. We need add checking and limitations according to test result future.
35 changes: 21 additions & 14 deletions src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ import (
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/cdh"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/forwarder"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/podnetwork"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/securecomms/wnssh"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/userdata"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/util"
provider "github.com/confidential-containers/cloud-api-adaptor/src/cloud-providers"
putil "github.com/confidential-containers/cloud-api-adaptor/src/cloud-providers/util"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-providers/util/cloudinit"

"github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor/pkg/securecomms/wnssh"
)

const (
Expand Down Expand Up @@ -286,7 +286,25 @@ func (s *cloudService) CreateVM(ctx context.Context, req *pb.CreateVMRequest) (r
},
}

if s.aaKBCParams != "" {
if authJSON != nil {
if len(authJSON) > cloudinit.DefaultAuthfileLimit {
logger.Printf("Credentials file is too large to be included in cloud-config")
} else {
cloudConfig.WriteFiles = append(cloudConfig.WriteFiles, cloudinit.WriteFile{
Path: AuthFilePath,
Content: string(authJSON),
})
}
}

initdataStr := util.GetInitdataFromAnnotation(req.Annotations)
logger.Printf("initdata: %s", initdataStr)
if initdataStr != "" {
cloudConfig.WriteFiles = append(cloudConfig.WriteFiles, cloudinit.WriteFile{
Path: userdata.InitdataPath,
Content: initdataStr,
})
} else if s.aaKBCParams != "" { // Keep AA_KBC_PARAMS support as it is used by e2e test, KBS is dynamic k8s service in e2e test
logger.Printf("aaKBCParams: %s, support cc_kbc::*", s.aaKBCParams)
toml, err := cdh.CreateConfigFile(s.aaKBCParams)
if err != nil {
Expand All @@ -307,17 +325,6 @@ func (s *cloudService) CreateVM(ctx context.Context, req *pb.CreateVMRequest) (r
})
}

if authJSON != nil {
if len(authJSON) > cloudinit.DefaultAuthfileLimit {
logger.Printf("Credentials file is too large to be included in cloud-config")
} else {
cloudConfig.WriteFiles = append(cloudConfig.WriteFiles, cloudinit.WriteFile{
Path: AuthFilePath,
Content: string(authJSON),
})
}
}

sandbox := &sandbox{
id: sid,
podName: pod,
Expand Down
2 changes: 1 addition & 1 deletion src/cloud-api-adaptor/pkg/cdh/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

const (
ConfigFilePath = "/run/confidential-containers/cdh.toml"
ConfigFilePath = "/run/peerpod/cdh.toml"
Socket = "unix:///run/confidential-containers/cdh.sock"
)

Expand Down
Loading

0 comments on commit b4f8b98

Please sign in to comment.