mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-04-19 15:05:57 -04:00
Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ea5cdfb247 | ||
![]() |
b34d9dc9d4 | ||
![]() |
79832a8f2a | ||
![]() |
c64068557c | ||
![]() |
4db8b2c272 | ||
![]() |
d2e1880f3e | ||
![]() |
0f2f1d3fd2 | ||
![]() |
50861c76af | ||
![]() |
b4820c9aa9 | ||
![]() |
027fd82206 | ||
![]() |
3dedcbd2ff | ||
![]() |
010323f890 | ||
![]() |
10c20f6f0b | ||
![]() |
0a09b02e71 | ||
![]() |
dec19769c5 | ||
![]() |
7af3fd7fda | ||
![]() |
83c748a9e8 | ||
![]() |
a88f9d8df4 | ||
![]() |
02e6cb4a2e | ||
![]() |
ad8458d0ac | ||
![]() |
938d0ceb00 | ||
![]() |
d8a734dc08 | ||
![]() |
3fa357786e | ||
![]() |
98d5998057 | ||
![]() |
c8ae092298 | ||
![]() |
6181381c66 | ||
![]() |
d6d9ef437c | ||
![]() |
d1a22a725e | ||
![]() |
e50e97dff6 | ||
![]() |
6e8cd2ad69 | ||
![]() |
a546648074 | ||
![]() |
f15380a70e | ||
![]() |
07db825756 | ||
![]() |
a3c5f3d445 | ||
![]() |
536bf6a35a | ||
![]() |
c123866358 | ||
![]() |
7238e2f895 | ||
![]() |
643b1ed4ac | ||
![]() |
a5e73b48da | ||
![]() |
e893b03eda | ||
![]() |
e7897a7468 | ||
![]() |
3d7b8c3596 | ||
![]() |
1f623c8658 | ||
![]() |
e9dc722b1f | ||
![]() |
839543dcc1 | ||
![]() |
228f168b0f | ||
![]() |
8db20665fd |
2
.github/actions/versionsapi/Dockerfile
vendored
2
.github/actions/versionsapi/Dockerfile
vendored
@ -1,4 +1,4 @@
|
||||
FROM golang:1.22.0@sha256:7b297d9abee021bab9046e492506b3c2da8a3722cbf301653186545ecc1e00bb as builder
|
||||
FROM golang:1.22.1@sha256:34ce21a9696a017249614876638ea37ceca13cdd88f582caad06f87a8aa45bf3 as builder
|
||||
|
||||
# Download project root dependencies
|
||||
WORKDIR /workspace
|
||||
|
2
.github/workflows/build-ccm-gcp.yml
vendored
2
.github/workflows/build-ccm-gcp.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
with:
|
||||
go-version: "1.22.0"
|
||||
go-version: "1.22.1"
|
||||
cache: false
|
||||
|
||||
- name: Install Crane
|
||||
|
@ -69,7 +69,7 @@ jobs:
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
with:
|
||||
go-version: "1.22.0"
|
||||
go-version: "1.22.1"
|
||||
cache: false
|
||||
|
||||
- name: Determine version
|
||||
|
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@ -40,7 +40,7 @@ jobs:
|
||||
if: matrix.language == 'go'
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
with:
|
||||
go-version: "1.22.0"
|
||||
go-version: "1.22.1"
|
||||
cache: false
|
||||
|
||||
- name: Initialize CodeQL
|
||||
|
4
.github/workflows/draft-release.yml
vendored
4
.github/workflows/draft-release.yml
vendored
@ -316,14 +316,14 @@ jobs:
|
||||
- provenance-subjects
|
||||
# This must not be pinned to digest. See:
|
||||
# https://github.com/slsa-framework/slsa-github-generator#referencing-slsa-builders-and-generators
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.10.0
|
||||
with:
|
||||
base64-subjects: "${{ needs.provenance-subjects.outputs.provenance-subjects }}"
|
||||
|
||||
provenance-verify:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
SLSA_VERIFIER_VERSION: "2.0.1"
|
||||
SLSA_VERIFIER_VERSION: "2.5.1"
|
||||
needs:
|
||||
- build-cli
|
||||
- provenance
|
||||
|
18
.github/workflows/e2e-test-provider-example.yml
vendored
18
.github/workflows/e2e-test-provider-example.yml
vendored
@ -83,14 +83,6 @@ jobs:
|
||||
ref: main
|
||||
stream: nightly
|
||||
|
||||
- name: Create resource prefix
|
||||
id: create-prefix
|
||||
shell: bash
|
||||
run: |
|
||||
run_id=${{ github.run_id }}
|
||||
last_three="${run_id: -3}"
|
||||
echo "prefix=e2e-${last_three}" | tee -a "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Determine cloudprovider from attestation variant
|
||||
id: determine
|
||||
shell: bash
|
||||
@ -124,6 +116,16 @@ jobs:
|
||||
buildBuddyApiKey: ${{ secrets.BUILDBUDDY_ORG_API_KEY }}
|
||||
nixTools: terraform
|
||||
|
||||
- name: Create prefix
|
||||
id: create-prefix
|
||||
shell: bash
|
||||
run: |
|
||||
uuid=$(uuidgen | tr "[:upper:]" "[:lower:]")
|
||||
uuid="${uuid%%-*}"
|
||||
uuid="${uuid: -3}" # Final resource name must be no longer than 10 characters on AWS
|
||||
echo "uuid=${uuid}" | tee -a "${GITHUB_OUTPUT}"
|
||||
echo "prefix=e2e-${uuid}" | tee -a "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Build Constellation provider and CLI # CLI is needed for the upgrade assert and container push is needed for the microservice upgrade
|
||||
working-directory: ${{ github.workspace }}
|
||||
id: build
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -233,7 +233,7 @@ jobs:
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
with:
|
||||
go-version: "1.22.0"
|
||||
go-version: "1.22.1"
|
||||
cache: true
|
||||
|
||||
- name: Build generateMeasurements tool
|
||||
|
2
.github/workflows/test-operator-codegen.yml
vendored
2
.github/workflows/test-operator-codegen.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
with:
|
||||
go-version: "1.22.0"
|
||||
go-version: "1.22.1"
|
||||
cache: true
|
||||
|
||||
- name: Run code generation
|
||||
|
1
3rdparty/bazel/org_golang/BUILD.bazel
vendored
Normal file
1
3rdparty/bazel/org_golang/BUILD.bazel
vendored
Normal file
@ -0,0 +1 @@
|
||||
exports_files(["go_tls_max_handshake_size.patch"])
|
11
3rdparty/bazel/org_golang/go_tls_max_handshake_size.patch
vendored
Normal file
11
3rdparty/bazel/org_golang/go_tls_max_handshake_size.patch
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
--- src/crypto/tls/common.go
|
||||
+++ src/crypto/tls/common.go
|
||||
@@ -62,7 +62,7 @@
|
||||
maxCiphertext = 16384 + 2048 // maximum ciphertext payload length
|
||||
maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3
|
||||
recordHeaderLen = 5 // record header length
|
||||
- maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
|
||||
+ maxHandshake = 262144 // maximum handshake we support (protocol max is 16 MB)
|
||||
maxUselessRecords = 16 // maximum number of consecutive non-advancing records
|
||||
)
|
||||
|
2
3rdparty/gcp-guest-agent/Dockerfile
vendored
2
3rdparty/gcp-guest-agent/Dockerfile
vendored
@ -6,7 +6,7 @@ RUN apt-get update && apt-get install -y \
|
||||
git
|
||||
|
||||
# Install Go
|
||||
ARG GO_VER=1.22.0
|
||||
ARG GO_VER=1.22.1
|
||||
RUN wget -q https://go.dev/dl/go${GO_VER}.linux-amd64.tar.gz && \
|
||||
tar -C /usr/local -xzf go${GO_VER}.linux-amd64.tar.gz && \
|
||||
rm go${GO_VER}.linux-amd64.tar.gz
|
||||
|
@ -165,11 +165,17 @@ load("//bazel/toolchains:go_module_deps.bzl", "go_dependencies")
|
||||
# gazelle:repository_macro bazel/toolchains/go_module_deps.bzl%go_dependencies
|
||||
go_dependencies()
|
||||
|
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
|
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_download_sdk", "go_register_toolchains", "go_rules_dependencies")
|
||||
|
||||
go_download_sdk(
|
||||
name = "go_sdk",
|
||||
patches = ["//3rdparty/bazel/org_golang:go_tls_max_handshake_size.patch"],
|
||||
version = "1.22.1",
|
||||
)
|
||||
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains(version = "1.22.0")
|
||||
go_register_toolchains()
|
||||
|
||||
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
|
||||
|
||||
|
@ -26,7 +26,7 @@ noHeader=$(
|
||||
--exclude-dir 3rdparty \
|
||||
--exclude-dir build \
|
||||
-e'SPDX-License-Identifier: AGPL-3.0-only' \
|
||||
-e'DO NOT EDIT'
|
||||
-e'DO NOT EDIT' | { grep -v internal/cloud/openstack/clouds || true; }
|
||||
)
|
||||
|
||||
if [[ -z ${noHeader} ]]; then
|
||||
|
@ -6933,8 +6933,8 @@ def go_dependencies():
|
||||
build_file_generation = "on",
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "google.golang.org/protobuf",
|
||||
sum = "h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=",
|
||||
version = "v1.32.0",
|
||||
sum = "h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=",
|
||||
version = "v1.33.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_crypto",
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.22.1
|
||||
// source: bootstrapper/initproto/init.proto
|
||||
|
||||
|
@ -150,6 +150,7 @@ func (c *JoinClient) Start(cleaner cleaner) {
|
||||
return
|
||||
} else if isUnrecoverable(err) {
|
||||
c.log.With(slog.Any("error", err)).Error("Unrecoverable error occurred")
|
||||
// TODO(burgerdev): this should eventually lead to a full node reset
|
||||
return
|
||||
}
|
||||
c.log.With(slog.Any("error", err)).Warn("Join failed for all available endpoints")
|
||||
@ -310,7 +311,15 @@ func (c *JoinClient) startNodeAndJoin(ticket *joinproto.IssueJoinTicketResponse,
|
||||
CACertHashes: []string{ticket.DiscoveryTokenCaCertHash},
|
||||
}
|
||||
|
||||
if err := c.joiner.JoinCluster(ctx, btd, c.role, ticket.KubernetesComponents, c.log); err != nil {
|
||||
// We currently cannot recover from any failure in this function. Joining the k8s cluster
|
||||
// sometimes fails transiently, and we don't want to brick the node because of that.
|
||||
for i := 0; i < 3; i++ {
|
||||
err = c.joiner.JoinCluster(ctx, btd, c.role, ticket.KubernetesComponents, c.log)
|
||||
if err != nil {
|
||||
c.log.Error("failed to join k8s cluster", "role", c.role, "attempt", i, "error", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("joining Kubernetes cluster: %w", err)
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@ func TestClient(t *testing.T) {
|
||||
apiAnswers []any
|
||||
wantLock bool
|
||||
wantJoin bool
|
||||
wantNumJoins int
|
||||
}{
|
||||
"on worker: metadata self: errors occur": {
|
||||
role: role.Worker,
|
||||
@ -168,12 +169,26 @@ func TestClient(t *testing.T) {
|
||||
listAnswer{instances: peers},
|
||||
issueJoinTicketAnswer{},
|
||||
},
|
||||
clusterJoiner: &stubClusterJoiner{joinClusterErr: someErr},
|
||||
clusterJoiner: &stubClusterJoiner{numBadCalls: -1, joinClusterErr: someErr},
|
||||
nodeLock: newFakeLock(),
|
||||
disk: &stubDisk{},
|
||||
wantJoin: true,
|
||||
wantLock: true,
|
||||
},
|
||||
"on control plane: joinCluster fails transiently": {
|
||||
role: role.ControlPlane,
|
||||
apiAnswers: []any{
|
||||
selfAnswer{instance: controlSelf},
|
||||
listAnswer{instances: peers},
|
||||
issueJoinTicketAnswer{},
|
||||
},
|
||||
clusterJoiner: &stubClusterJoiner{numBadCalls: 1, joinClusterErr: someErr},
|
||||
nodeLock: newFakeLock(),
|
||||
disk: &stubDisk{},
|
||||
wantJoin: true,
|
||||
wantLock: true,
|
||||
wantNumJoins: 2,
|
||||
},
|
||||
"on control plane: node already locked": {
|
||||
role: role.ControlPlane,
|
||||
apiAnswers: []any{
|
||||
@ -250,9 +265,12 @@ func TestClient(t *testing.T) {
|
||||
client.Stop()
|
||||
|
||||
if tc.wantJoin {
|
||||
assert.True(tc.clusterJoiner.joinClusterCalled)
|
||||
assert.Greater(tc.clusterJoiner.joinClusterCalled, 0)
|
||||
} else {
|
||||
assert.False(tc.clusterJoiner.joinClusterCalled)
|
||||
assert.Equal(0, tc.clusterJoiner.joinClusterCalled)
|
||||
}
|
||||
if tc.wantNumJoins > 0 {
|
||||
assert.GreaterOrEqual(tc.clusterJoiner.joinClusterCalled, tc.wantNumJoins)
|
||||
}
|
||||
if tc.wantLock {
|
||||
assert.False(client.nodeLock.TryLockOnce(nil)) // lock should be locked
|
||||
@ -398,12 +416,17 @@ type issueJoinTicketAnswer struct {
|
||||
}
|
||||
|
||||
type stubClusterJoiner struct {
|
||||
joinClusterCalled bool
|
||||
joinClusterCalled int
|
||||
numBadCalls int
|
||||
joinClusterErr error
|
||||
}
|
||||
|
||||
func (j *stubClusterJoiner) JoinCluster(context.Context, *kubeadm.BootstrapTokenDiscovery, role.Role, components.Components, *slog.Logger) error {
|
||||
j.joinClusterCalled = true
|
||||
j.joinClusterCalled++
|
||||
if j.numBadCalls == 0 {
|
||||
return nil
|
||||
}
|
||||
j.numBadCalls--
|
||||
return j.joinClusterErr
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ go_library(
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/cloud/gcpshared",
|
||||
"//internal/cloud/openstack",
|
||||
"//internal/cloud/openstack/clouds",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
"//internal/constellation",
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/gcpshared"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/openstack"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/openstack/clouds"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
@ -38,15 +39,23 @@ func GetMarshaledServiceAccountURI(config *config.Config, fileHandler file.Handl
|
||||
}
|
||||
|
||||
case cloudprovider.OpenStack:
|
||||
cloudsYAML, err := clouds.ReadCloudsYAML(fileHandler, config.Provider.OpenStack.CloudsYAMLPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("reading clouds.yaml: %w", err)
|
||||
}
|
||||
cloud, ok := cloudsYAML.Clouds[config.Provider.OpenStack.Cloud]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("cloud %q not found in clouds.yaml", config.Provider.OpenStack.Cloud)
|
||||
}
|
||||
payload.OpenStack = openstack.AccountKey{
|
||||
AuthURL: config.Provider.OpenStack.AuthURL,
|
||||
Username: config.Provider.OpenStack.Username,
|
||||
Password: config.Provider.OpenStack.Password,
|
||||
ProjectID: config.Provider.OpenStack.ProjectID,
|
||||
ProjectName: config.Provider.OpenStack.ProjectName,
|
||||
UserDomainName: config.Provider.OpenStack.UserDomainName,
|
||||
ProjectDomainName: config.Provider.OpenStack.ProjectDomainName,
|
||||
RegionName: config.Provider.OpenStack.RegionName,
|
||||
AuthURL: cloud.AuthInfo.AuthURL,
|
||||
Username: cloud.AuthInfo.Username,
|
||||
Password: cloud.AuthInfo.Password,
|
||||
ProjectID: cloud.AuthInfo.ProjectID,
|
||||
ProjectName: cloud.AuthInfo.ProjectName,
|
||||
UserDomainName: cloud.AuthInfo.UserDomainName,
|
||||
ProjectDomainName: cloud.AuthInfo.ProjectDomainName,
|
||||
RegionName: cloud.RegionName,
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -257,11 +257,9 @@ func openStackTerraformVars(conf *config.Config, imageRef string) (*terraform.Op
|
||||
return &terraform.OpenStackClusterVariables{
|
||||
Name: conf.Name,
|
||||
Cloud: toPtr(conf.Provider.OpenStack.Cloud),
|
||||
OpenStackCloudsYAMLPath: conf.Provider.OpenStack.CloudsYAMLPath,
|
||||
FloatingIPPoolID: conf.Provider.OpenStack.FloatingIPPoolID,
|
||||
ImageID: imageRef,
|
||||
OpenstackUserDomainName: conf.Provider.OpenStack.UserDomainName,
|
||||
OpenstackUsername: conf.Provider.OpenStack.Username,
|
||||
OpenstackPassword: conf.Provider.OpenStack.Password,
|
||||
Debug: conf.IsDebugCluster(),
|
||||
NodeGroups: nodeGroups,
|
||||
CustomEndpoint: conf.CustomEndpoint,
|
||||
|
@ -40,7 +40,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
||||
"github.com/edgelesssys/constellation/v2/internal/semver"
|
||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||
"github.com/samber/slog-multi"
|
||||
slogmulti "github.com/samber/slog-multi"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
@ -365,7 +365,7 @@ func (a *applyCmd) apply(
|
||||
}
|
||||
|
||||
// Check license
|
||||
a.checkLicenseFile(cmd, conf.GetProvider())
|
||||
a.checkLicenseFile(cmd, conf.GetProvider(), conf.UseMarketplaceImage())
|
||||
|
||||
// Now start actually running the apply command
|
||||
|
||||
@ -844,7 +844,7 @@ type applier interface {
|
||||
// methods required to install/upgrade Helm charts
|
||||
|
||||
PrepareHelmCharts(
|
||||
flags helm.Options, state *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags helm.Options, state *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (helm.Applier, bool, error)
|
||||
|
||||
// methods to interact with Kubernetes
|
||||
|
@ -554,7 +554,7 @@ func (s *stubConstellApplier) Init(context.Context, atls.Validator, *state.State
|
||||
|
||||
type helmApplier interface {
|
||||
PrepareHelmCharts(
|
||||
flags helm.Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags helm.Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (
|
||||
helm.Applier, bool, error)
|
||||
}
|
||||
|
@ -43,6 +43,18 @@ func (a *applyCmd) runHelmApply(cmd *cobra.Command, conf *config.Config, stateFi
|
||||
ApplyTimeout: a.flags.helmTimeout,
|
||||
AllowDestructive: helm.DenyDestructive,
|
||||
}
|
||||
if conf.Provider.OpenStack != nil {
|
||||
var deployYawolLoadBalancer bool
|
||||
if conf.Provider.OpenStack.DeployYawolLoadBalancer != nil {
|
||||
deployYawolLoadBalancer = *conf.Provider.OpenStack.DeployYawolLoadBalancer
|
||||
}
|
||||
options.OpenStackValues = &helm.OpenStackValues{
|
||||
DeployYawolLoadBalancer: deployYawolLoadBalancer,
|
||||
FloatingIPPoolID: conf.Provider.OpenStack.FloatingIPPoolID,
|
||||
YawolFlavorID: conf.Provider.OpenStack.YawolFlavorID,
|
||||
YawolImageID: conf.Provider.OpenStack.YawolImageID,
|
||||
}
|
||||
}
|
||||
|
||||
a.log.Debug("Getting service account URI")
|
||||
serviceAccURI, err := cloudcmd.GetMarshaledServiceAccountURI(conf, a.fileHandler)
|
||||
@ -51,7 +63,7 @@ func (a *applyCmd) runHelmApply(cmd *cobra.Command, conf *config.Config, stateFi
|
||||
}
|
||||
|
||||
a.log.Debug("Preparing Helm charts")
|
||||
executor, includesUpgrades, err := a.applier.PrepareHelmCharts(options, stateFile, serviceAccURI, masterSecret, conf.Provider.OpenStack)
|
||||
executor, includesUpgrades, err := a.applier.PrepareHelmCharts(options, stateFile, serviceAccURI, masterSecret)
|
||||
if errors.Is(err, helm.ErrConfirmationMissing) {
|
||||
if !a.flags.yes {
|
||||
cmd.PrintErrln("WARNING: Upgrading cert-manager will destroy all custom resources you have manually created that are based on the current version of cert-manager.")
|
||||
@ -65,7 +77,7 @@ func (a *applyCmd) runHelmApply(cmd *cobra.Command, conf *config.Config, stateFi
|
||||
}
|
||||
}
|
||||
options.AllowDestructive = helm.AllowDestructive
|
||||
executor, includesUpgrades, err = a.applier.PrepareHelmCharts(options, stateFile, serviceAccURI, masterSecret, conf.Provider.OpenStack)
|
||||
executor, includesUpgrades, err = a.applier.PrepareHelmCharts(options, stateFile, serviceAccURI, masterSecret)
|
||||
}
|
||||
var upgradeErr *compatibility.InvalidUpgradeError
|
||||
if err != nil {
|
||||
|
@ -128,7 +128,7 @@ func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file
|
||||
|
||||
// createConfigWithAttestationVariant creates a config file for the given provider.
|
||||
func createConfigWithAttestationVariant(provider cloudprovider.Provider, rawProvider string, attestationVariant variant.Variant) (*config.Config, error) {
|
||||
conf := config.Default().WithOpenStackProviderDefaults(rawProvider)
|
||||
conf := config.Default().WithOpenStackProviderDefaults(provider, rawProvider)
|
||||
conf.RemoveProviderExcept(provider)
|
||||
|
||||
// set a lower default for QEMU's state disk
|
||||
|
@ -140,7 +140,7 @@ func TestConfigGenerateDefaultProviderSpecific(t *testing.T) {
|
||||
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
||||
cmd := newConfigGenerateCmd()
|
||||
|
||||
wantConf := config.Default().WithOpenStackProviderDefaults(tc.rawProvider)
|
||||
wantConf := config.Default().WithOpenStackProviderDefaults(cloudprovider.OpenStack, tc.rawProvider)
|
||||
wantConf.RemoveProviderAndAttestationExcept(tc.provider)
|
||||
|
||||
cg := &configGenerateCmd{
|
||||
|
@ -38,6 +38,8 @@ Azure Trusted Launch instance types:
|
||||
%v
|
||||
GCP instance types:
|
||||
%v
|
||||
STACKIT instance types:
|
||||
%v
|
||||
`,
|
||||
formatInstanceTypes(instancetypes.AWSSNPSupportedInstanceFamilies),
|
||||
formatInstanceTypes(instancetypes.AWSSupportedInstanceFamilies),
|
||||
@ -45,6 +47,7 @@ GCP instance types:
|
||||
formatInstanceTypes(instancetypes.AzureSNPInstanceTypes),
|
||||
formatInstanceTypes(instancetypes.AzureTrustedLaunchInstanceTypes),
|
||||
formatInstanceTypes(instancetypes.GCPInstanceTypes),
|
||||
formatInstanceTypes(instancetypes.STACKITInstanceTypes),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ type stubHelmApplier struct {
|
||||
}
|
||||
|
||||
func (s stubHelmApplier) PrepareHelmCharts(
|
||||
_ helm.Options, _ *state.State, _ string, _ uri.MasterSecret, _ *config.OpenStackConfig,
|
||||
_ helm.Options, _ *state.State, _ string, _ uri.MasterSecret,
|
||||
) (helm.Applier, bool, error) {
|
||||
return stubRunner{}, false, s.err
|
||||
}
|
||||
|
@ -22,18 +22,22 @@ import (
|
||||
// with the license server. If no license file is present or if errors
|
||||
// occur during the check, the user is informed and the community license
|
||||
// is used. It is a no-op in the open source version of Constellation.
|
||||
func (a *applyCmd) checkLicenseFile(cmd *cobra.Command, csp cloudprovider.Provider) {
|
||||
func (a *applyCmd) checkLicenseFile(cmd *cobra.Command, csp cloudprovider.Provider, useMarketplaceImage bool) {
|
||||
var licenseID string
|
||||
a.log.Debug("Running license check")
|
||||
|
||||
readBytes, err := a.fileHandler.Read(constants.LicenseFilename)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
cmd.Printf("Using community license.\n")
|
||||
switch {
|
||||
case useMarketplaceImage:
|
||||
cmd.Println("Using marketplace image billing.")
|
||||
licenseID = license.MarketplaceLicense
|
||||
case errors.Is(err, fs.ErrNotExist):
|
||||
cmd.Println("Using community license.")
|
||||
licenseID = license.CommunityLicense
|
||||
} else if err != nil {
|
||||
case err != nil:
|
||||
cmd.Printf("Error: %v\nContinuing with community license.\n", err)
|
||||
licenseID = license.CommunityLicense
|
||||
} else {
|
||||
default:
|
||||
cmd.Printf("Constellation license found!\n")
|
||||
licenseID, err = license.FromBytes(readBytes)
|
||||
if err != nil {
|
||||
@ -43,9 +47,11 @@ func (a *applyCmd) checkLicenseFile(cmd *cobra.Command, csp cloudprovider.Provid
|
||||
}
|
||||
|
||||
quota, err := a.applier.CheckLicense(cmd.Context(), csp, !a.flags.skipPhases.contains(skipInitPhase), licenseID)
|
||||
if err != nil {
|
||||
if err != nil && !useMarketplaceImage {
|
||||
cmd.Printf("Unable to contact license server.\n")
|
||||
cmd.Printf("Please keep your vCPU quota in mind.\n")
|
||||
} else if licenseID == license.MarketplaceLicense {
|
||||
// Do nothing. Billing is handled by the marketplace.
|
||||
} else if licenseID == license.CommunityLicense {
|
||||
cmd.Printf("For details, see https://docs.edgeless.systems/constellation/overview/license\n")
|
||||
} else {
|
||||
|
@ -17,4 +17,4 @@ import (
|
||||
// with the license server. If no license file is present or if errors
|
||||
// occur during the check, the user is informed and the community license
|
||||
// is used. It is a no-op in the open source version of Constellation.
|
||||
func (a *applyCmd) checkLicenseFile(*cobra.Command, cloudprovider.Provider) {}
|
||||
func (a *applyCmd) checkLicenseFile(*cobra.Command, cloudprovider.Provider, bool) {}
|
||||
|
@ -376,9 +376,9 @@ type mockApplier struct {
|
||||
}
|
||||
|
||||
func (m *mockApplier) PrepareHelmCharts(
|
||||
helmOpts helm.Options, stateFile *state.State, str string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
helmOpts helm.Options, stateFile *state.State, str string, masterSecret uri.MasterSecret,
|
||||
) (helm.Applier, bool, error) {
|
||||
args := m.Called(helmOpts, stateFile, helmOpts, str, masterSecret, openStackCfg)
|
||||
args := m.Called(helmOpts, stateFile, helmOpts, str, masterSecret)
|
||||
return args.Get(0).(helm.Applier), args.Bool(1), args.Error(2)
|
||||
}
|
||||
|
||||
|
@ -278,20 +278,16 @@ type OpenStackClusterVariables struct {
|
||||
Name string `hcl:"name" cty:"name"`
|
||||
// NodeGroups is a map of node groups to create.
|
||||
NodeGroups map[string]OpenStackNodeGroup `hcl:"node_groups" cty:"node_groups"`
|
||||
// Cloud is the (optional) name of the OpenStack cloud to use when reading the "clouds.yaml" configuration file. If empty, environment variables are used.
|
||||
// Cloud is the name of the OpenStack cloud to use when reading the "clouds.yaml" configuration file. If empty, environment variables are used.
|
||||
Cloud *string `hcl:"cloud" cty:"cloud"`
|
||||
// OpenStackCloudsYAMLPath is the path to the OpenStack clouds.yaml file
|
||||
OpenStackCloudsYAMLPath string `hcl:"openstack_clouds_yaml_path" cty:"openstack_clouds_yaml_path"`
|
||||
// (STACKIT only) STACKITProjectID is the ID of the STACKIT project to use.
|
||||
STACKITProjectID string `hcl:"stackit_project_id" cty:"stackit_project_id"`
|
||||
// FloatingIPPoolID is the ID of the OpenStack floating IP pool to use for public IPs.
|
||||
FloatingIPPoolID string `hcl:"floating_ip_pool_id" cty:"floating_ip_pool_id"`
|
||||
// ImageID is the ID of the OpenStack image to use.
|
||||
ImageID string `hcl:"image_id" cty:"image_id"`
|
||||
// OpenstackUserDomainName is the OpenStack user domain name to use.
|
||||
OpenstackUserDomainName string `hcl:"openstack_user_domain_name" cty:"openstack_user_domain_name"`
|
||||
// OpenstackUsername is the OpenStack user name to use.
|
||||
OpenstackUsername string `hcl:"openstack_username" cty:"openstack_username"`
|
||||
// OpenstackPassword is the OpenStack password to use.
|
||||
OpenstackPassword string `hcl:"openstack_password" cty:"openstack_password"`
|
||||
// Debug is true if debug mode is enabled.
|
||||
Debug bool `hcl:"debug" cty:"debug"`
|
||||
// CustomEndpoint is the (optional) custom dns hostname for the kubernetes api server.
|
||||
|
@ -254,11 +254,9 @@ func TestOpenStackClusterVariables(t *testing.T) {
|
||||
vars := OpenStackClusterVariables{
|
||||
Name: "cluster-name",
|
||||
Cloud: toPtr("my-cloud"),
|
||||
OpenStackCloudsYAMLPath: "~/.config/openstack/clouds.yaml",
|
||||
FloatingIPPoolID: "fip-pool-0123456789abcdef",
|
||||
ImageID: "8e10b92d-8f7a-458c-91c6-59b42f82ef81",
|
||||
OpenstackUserDomainName: "my-user-domain",
|
||||
OpenstackUsername: "my-username",
|
||||
OpenstackPassword: "my-password",
|
||||
Debug: true,
|
||||
STACKITProjectID: "my-stackit-project-id",
|
||||
NodeGroups: map[string]OpenStackNodeGroup{
|
||||
@ -287,12 +285,10 @@ node_groups = {
|
||||
}
|
||||
}
|
||||
cloud = "my-cloud"
|
||||
openstack_clouds_yaml_path = "~/.config/openstack/clouds.yaml"
|
||||
stackit_project_id = "my-stackit-project-id"
|
||||
floating_ip_pool_id = "fip-pool-0123456789abcdef"
|
||||
image_id = "8e10b92d-8f7a-458c-91c6-59b42f82ef81"
|
||||
openstack_user_domain_name = "my-user-domain"
|
||||
openstack_username = "my-username"
|
||||
openstack_password = "my-password"
|
||||
debug = true
|
||||
custom_endpoint = "example.com"
|
||||
internal_load_balancer = false
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.22.1
|
||||
// source: debugd/service/debugd.proto
|
||||
|
||||
|
@ -12,9 +12,11 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"log/syslog"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/disk-mapper/internal/diskencryption"
|
||||
"github.com/edgelesssys/constellation/v2/disk-mapper/internal/recoveryserver"
|
||||
@ -48,6 +50,21 @@ const (
|
||||
)
|
||||
|
||||
func main() {
|
||||
runErr := run()
|
||||
if runErr == nil {
|
||||
return
|
||||
}
|
||||
syslogWriter, err := syslog.New(syslog.LOG_EMERG|syslog.LOG_KERN, "disk-mapper")
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
_ = syslogWriter.Err(runErr.Error())
|
||||
_ = syslogWriter.Emerg("disk-mapper has failed. In most cases, this is due to a misconfiguration or transient error with the infrastructure.")
|
||||
time.Sleep(time.Minute) // sleep to allow the message to be written to syslog and seen by the user
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func run() error {
|
||||
csp := flag.String("csp", "", "Cloud Service Provider the image is running on")
|
||||
verbosity := flag.Int("v", 0, logger.CmdLineVerbosityDescription)
|
||||
|
||||
@ -60,12 +77,12 @@ func main() {
|
||||
attestVariant, err := variant.FromString(os.Getenv(constants.AttestationVariant))
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error("Failed to parse attestation variant")
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
issuer, err := choose.Issuer(attestVariant, log)
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error("Failed to select issuer")
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// set up metadata API
|
||||
@ -78,36 +95,36 @@ func main() {
|
||||
diskPath, err = filepath.EvalSymlinks(awsStateDiskPath)
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error("Unable to resolve Azure state disk path")
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
metadataClient, err = awscloud.New(context.Background())
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error("Failed to set up AWS metadata client")
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
case cloudprovider.Azure:
|
||||
diskPath, err = filepath.EvalSymlinks(azureStateDiskPath)
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error("Unable to resolve Azure state disk path")
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
metadataClient, err = azurecloud.New(context.Background())
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error("Failed to set up Azure metadata client")
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
case cloudprovider.GCP:
|
||||
diskPath, err = filepath.EvalSymlinks(gcpStateDiskPath)
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error("Unable to resolve GCP state disk path")
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
gcpMeta, err := gcpcloud.New(context.Background())
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error(("Failed to create GCP metadata client"))
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
defer gcpMeta.Close()
|
||||
metadataClient = gcpMeta
|
||||
@ -117,7 +134,7 @@ func main() {
|
||||
metadataClient, err = openstack.New(context.Background())
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error(("Failed to create OpenStack metadata client"))
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
case cloudprovider.QEMU:
|
||||
@ -126,14 +143,14 @@ func main() {
|
||||
|
||||
default:
|
||||
log.Error(fmt.Sprintf("CSP %s is not supported by Constellation", *csp))
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// initialize device mapper
|
||||
mapper, free, err := diskencryption.New(diskPath, log)
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error(("Failed to initialize device mapper"))
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
defer free()
|
||||
|
||||
@ -156,7 +173,7 @@ func main() {
|
||||
|
||||
if err := setupManger.LogDevices(); err != nil {
|
||||
log.With(slog.Any("error", err)).Error(("Failed to log devices"))
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// prepare the state disk
|
||||
@ -166,7 +183,7 @@ func main() {
|
||||
self, err = metadataClient.Self(context.Background())
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error(("Failed to get self metadata"))
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
rejoinClient := rejoinclient.New(
|
||||
dialer.New(issuer, nil, &net.Dialer{}),
|
||||
@ -189,6 +206,7 @@ func main() {
|
||||
}
|
||||
if err != nil {
|
||||
log.With(slog.Any("error", err)).Error(("Failed to prepare state disk"))
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.22.1
|
||||
// source: disk-mapper/recoverproto/recover.proto
|
||||
|
||||
|
@ -217,6 +217,38 @@ The latter means that the value can be generated offline and compared to the one
|
||||
| 15 | ClusterID | Constellation Bootstrapper | Yes |
|
||||
| 16–23 | Unused | - | - |
|
||||
|
||||
</tabItem>
|
||||
<tabItem value="stackit" label="STACKIT">
|
||||
|
||||
Constellation uses a hypervisor-based vTPM for runtime measurements.
|
||||
|
||||
The vTPM adheres to the [TPM 2.0](https://trustedcomputinggroup.org/resource/tpm-library-specification/) specification.
|
||||
The VMs are attested by obtaining signed PCR values over the VM's boot configuration from the TPM and comparing them to a known, good state (measured boot).
|
||||
|
||||
The following table lists all PCR values of the vTPM and the measured components.
|
||||
It also lists what components of the boot chain did the measurements and if the value is reproducible and verifiable.
|
||||
The latter means that the value can be generated offline and compared to the one in the vTPM.
|
||||
|
||||
| PCR | Components | Measured by | Reproducible and verifiable |
|
||||
| ----------- | ---------------------------------------------------------------- | -------------------------------------- | --------------------------- |
|
||||
| 0 | Firmware | STACKIT | No |
|
||||
| 1 | Firmware | STACKIT | No |
|
||||
| 2 | Firmware | STACKIT | No |
|
||||
| 3 | Firmware | STACKIT | No |
|
||||
| 4 | Constellation Bootloader, Kernel, initramfs, Kernel command line | STACKIT, Constellation Bootloader | Yes |
|
||||
| 5 | Firmware | STACKIT | No |
|
||||
| 6 | Firmware | STACKIT | No |
|
||||
| 7 | Secure Boot Policy | STACKIT, Constellation Bootloader | No |
|
||||
| 8 | - | - | - |
|
||||
| 9 | initramfs, Kernel command line | Linux Kernel | Yes |
|
||||
| 10 | User space | Linux IMA | No[^1] |
|
||||
| 11 | Unified Kernel Image components | Constellation Bootloader | Yes |
|
||||
| 12 | Reserved | (User space, Constellation Bootloader) | Yes |
|
||||
| 13 | Reserved | (Constellation Bootloader) | Yes |
|
||||
| 14 | Secure Boot State | Constellation Bootloader | No |
|
||||
| 15 | ClusterID | Constellation Bootstrapper | Yes |
|
||||
| 16–23 | Unused | - | - |
|
||||
|
||||
</tabItem>
|
||||
</tabs>
|
||||
|
||||
@ -251,13 +283,15 @@ You may customize certain parameters for verification of the attestation stateme
|
||||
</tabItem>
|
||||
<tabItem value="gcp" label="GCP">
|
||||
|
||||
On GCP, AMD SEV-ES is used to provide runtime encryption to the VMs.
|
||||
The hypervisor-based vTPM is used to establish trust in the VM via [runtime measurements](#runtime-measurements).
|
||||
There is no additional configuration available for GCP.
|
||||
|
||||
</tabItem>
|
||||
<tabItem value="aws" label="AWS">
|
||||
|
||||
On AWS, AMD SEV-SNP is used to provide runtime encryption to the VMs.
|
||||
An SEV-SNP attestation report is used to establish trust in the VM and it's vTPM.
|
||||
An SEV-SNP attestation report is used to establish trust in the VM.
|
||||
You may customize certain parameters for verification of the attestation statement using the Constellation config file.
|
||||
|
||||
* TCB versions
|
||||
@ -275,6 +309,13 @@ You may customize certain parameters for verification of the attestation stateme
|
||||
This is the intermediate certificate for verifying the SEV-SNP report's signature.
|
||||
If it's not specified, the CLI fetches it from the AMD key distribution server.
|
||||
|
||||
</tabItem>
|
||||
<tabItem value="stackit" label="STACKIT">
|
||||
|
||||
On STACKIT, AMD SEV-ES is used to provide runtime encryption to the VMs.
|
||||
The hypervisor-based vTPM is used to establish trust in the VM via [runtime measurements](#runtime-measurements).
|
||||
There is no additional configuration available for STACKIT.
|
||||
|
||||
</tabItem>
|
||||
</tabs>
|
||||
|
||||
|
@ -6,7 +6,7 @@ Constellation runs entirely in your cloud environment and can be controlled via
|
||||
|
||||
Make sure the following requirements are met:
|
||||
|
||||
* Your machine is running Linux or macOS
|
||||
* Your machine is running Linux, macOS, or Windows
|
||||
* You have admin rights on your machine
|
||||
* [kubectl](https://kubernetes.io/docs/tasks/tools/) is installed
|
||||
* Your CSP is Microsoft Azure, Google Cloud Platform (GCP), Amazon Web Services (AWS), or STACKIT
|
||||
@ -92,6 +92,29 @@ curl -LO https://github.com/edgelesssys/constellation/releases/latest/download/c
|
||||
sudo install constellation-darwin-amd64 /usr/local/bin/constellation
|
||||
```
|
||||
|
||||
</tabItem>
|
||||
|
||||
<tabItem value="windows-amd64" label="Windows (amd64)">
|
||||
|
||||
1. Download the CLI:
|
||||
|
||||
```bash
|
||||
Invoke-WebRequest -OutFile ./constellation.exe -Uri 'https://github.com/edgelesssys/constellation/releases/latest/download/constellation-windows-amd64.exe'
|
||||
```
|
||||
|
||||
2. [Verify the signature](../workflows/verify-cli.md) (optional)
|
||||
|
||||
3. Install the CLI under `C:\Program Files\Constellation\bin\constellation.exe`
|
||||
|
||||
3. Add the CLI to your PATH:
|
||||
|
||||
1. Open `Advanced system settings` by searching for the App in the Windows search
|
||||
2. Go to the `Advanced` tab
|
||||
3. Click `Environment Variables…`
|
||||
4. Click variable called `Path` and click `Edit…`
|
||||
5. Click `New`
|
||||
6. Enter the path to the folder containing the binary you want on your PATH: `C:\Program Files\Constellation\bin`
|
||||
|
||||
</tabItem>
|
||||
</tabs>
|
||||
|
||||
@ -374,7 +397,7 @@ Options and first steps are described in the [AWS CLI documentation](https://doc
|
||||
You need to authenticate with the infrastructure API (OpenStack) and create a service account (STACKIT API).
|
||||
|
||||
1. [Follow the STACKIT documentation](https://docs.stackit.cloud/stackit/en/step-1-generating-of-user-access-token-11763726.html) for obtaining a User Access Token (UAT) to use the infrastructure API
|
||||
2. Create a configuration file under `~/.config/openstack/clouds.yaml` with the credentials from the User Access Token
|
||||
2. Create a configuration file under `~/.config/openstack/clouds.yaml` (`%AppData%\openstack\clouds.yaml` on Windows) with the credentials from the User Access Token
|
||||
```yaml
|
||||
clouds:
|
||||
stackit:
|
||||
@ -391,7 +414,7 @@ You need to authenticate with the infrastructure API (OpenStack) and create a se
|
||||
```
|
||||
3. [Follow the STACKIT documentation](https://docs.stackit.cloud/stackit/en/getting-started-in-service-accounts-134415831.html) for creating a service account and an access token
|
||||
4. Assign the `editor` role to the service account by [following the documentation](https://docs.stackit.cloud/stackit/en/getting-started-in-service-accounts-134415831.html)
|
||||
5. Create a configuration file under `~/.stackit/credentials.json`
|
||||
5. Create a configuration file under `~/.stackit/credentials.json` (`%USERPROFILE%\.stackit\credentials.json` on Windows)
|
||||
```json
|
||||
{"STACKIT_SERVICE_ACCOUNT_TOKEN":"REPLACE_WITH_TOKEN"}
|
||||
```
|
||||
|
@ -14,13 +14,13 @@ For Constellation, the ideal environment provides the following:
|
||||
|
||||
The following table summarizes the state of features for different infrastructures as of June 2023.
|
||||
|
||||
| **Feature** | **Azure** | **GCP** | **AWS** | **OpenStack (Yoga)** |
|
||||
|-----------------------------------|-----------|---------|---------|----------------------|
|
||||
| **1. Custom images** | Yes | Yes | Yes | Yes |
|
||||
| **2. SEV-SNP or TDX** | Yes | Yes | Yes | Depends on kernel/HV |
|
||||
| **3. Raw guest attestation** | Yes | Yes | Yes | Depends on kernel/HV |
|
||||
| **4. Reviewable firmware** | No | No | Yes | Depends on kernel/HV |
|
||||
| **5. Confidential measured boot** | Yes | No | No | Depends on kernel/HV |
|
||||
| **Feature** | **Azure** | **GCP** | **AWS** | **STACKIT** | **OpenStack (Yoga)** |
|
||||
|-----------------------------------|-----------|---------|---------|--------------|----------------------|
|
||||
| **1. Custom images** | Yes | Yes | Yes | Yes | Yes |
|
||||
| **2. SEV-SNP or TDX** | Yes | Yes | Yes | No | Depends on kernel/HV |
|
||||
| **3. Raw guest attestation** | Yes | Yes | Yes | No | Depends on kernel/HV |
|
||||
| **4. Reviewable firmware** | No | No | Yes | No | Depends on kernel/HV |
|
||||
| **5. Confidential measured boot** | Yes | No | No | No | Depends on kernel/HV |
|
||||
|
||||
## Microsoft Azure
|
||||
|
||||
@ -53,6 +53,10 @@ However, regarding (5), attestation is partially based on the [NitroTPM](https:/
|
||||
Hence, the hypervisor is currently part of Constellation's TCB.
|
||||
Regarding (4), the [firmware is open source](https://github.com/aws/uefi) and can be reproducibly built.
|
||||
|
||||
## STACKIT
|
||||
|
||||
[STACKIT Compute Engine](https://www.stackit.de/en/product/stackit-compute-engine/) supports AMD SEV-ES. A vTPM is used for measured boot, which is a vTPM managed by STACKIT's hypervisor. Hence, the hypervisor is currently part of Constellation's TCB.
|
||||
|
||||
## OpenStack
|
||||
|
||||
OpenStack is an open-source cloud and infrastructure management software. It's used by many smaller CSPs and datacenters. In the latest *Yoga* version, OpenStack has basic support for CVMs. However, much depends on the employed kernel and hypervisor. Features (2)--(4) are likely to be a *Yes* with Linux kernel version 6.2. Thus, going forward, OpenStack on corresponding AMD or Intel hardware will be a viable underpinning for Constellation.
|
||||
|
@ -77,17 +77,17 @@ The Constellation CLI can also print the supported instance types with: `constel
|
||||
</tabItem>
|
||||
<tabItem value="stackit" label="STACKIT">
|
||||
|
||||
By default, Constellation uses `m1a.4cd` VMs (4 vCPUs, 32 GB RAM) to create your cluster.
|
||||
By default, Constellation uses `m1a.4cd` VMs (4 vCPUs, 30 GB RAM) to create your cluster.
|
||||
Optionally, you can switch to a different VM type by modifying `instanceType` in the configuration file.
|
||||
|
||||
The following instance types are known to be supported:
|
||||
|
||||
| name | vCPUs | GB RAM |
|
||||
|----------|-------|--------|
|
||||
| m1a.4cd | 4 | 32 |
|
||||
| m1a.8cd | 8 | 64 |
|
||||
| m1a.4cd | 4 | 30 |
|
||||
| m1a.8cd | 8 | 60 |
|
||||
| m1a.16cd | 16 | 120 |
|
||||
| m1a.30cd | 30 | 238 |
|
||||
| m1a.30cd | 30 | 230 |
|
||||
|
||||
You can choose any of the SEV-enabled instance types. You can find a list of all supported instance types in the [STACKIT documentation](https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html).
|
||||
|
||||
@ -135,7 +135,7 @@ This configuration creates an additional node group `high_cpu` with a larger ins
|
||||
|
||||
You can use the field `zone` to specify what availability zone nodes of the group are placed in.
|
||||
On Azure, this field is empty by default and nodes are automatically spread across availability zones.
|
||||
STACKIT currently only offers SEV-enabled CPUs in the `eu01-1` zone.
|
||||
STACKIT currently offers SEV-enabled CPUs in the `eu01-1`, `eu01-2` and `eu01-3` zone.
|
||||
Consult the documentation of your cloud provider for more information:
|
||||
|
||||
* [AWS](https://aws.amazon.com/about-aws/global-infrastructure/regions_az/)
|
||||
|
@ -118,6 +118,37 @@ If this fails due to an unhealthy control plane, you will see log messages simil
|
||||
|
||||
This means that you have to recover the node manually.
|
||||
|
||||
</tabItem>
|
||||
<tabItem value="stackit" label="STACKIT">
|
||||
|
||||
First, open the STACKIT portal to view all servers in your project. Select individual control plane nodes `<cluster-name>-<UID>-control-plane-<UID>-<index>` and check that enough members are in a *Running* state.
|
||||
|
||||
Second, check the boot logs of these servers. Click on a server name and select **Overview**. Find the **Machine Setup** section and click on **Web console** > **Open console**.
|
||||
|
||||
In the serial console output, search for `Waiting for decryption key`.
|
||||
Similar output to the following means your node was restarted and needs to decrypt the [state disk](../architecture/images.md#state-disk):
|
||||
|
||||
```json
|
||||
{"level":"INFO","ts":"2022-09-08T10:21:53Z","caller":"cmd/main.go:55","msg":"Starting disk-mapper","version":"2.0.0","cloudProvider":"gcp"}
|
||||
{"level":"INFO","ts":"2022-09-08T10:21:53Z","logger":"setupManager","caller":"setup/setup.go:72","msg":"Preparing existing state disk"}
|
||||
{"level":"INFO","ts":"2022-09-08T10:21:53Z","logger":"rejoinClient","caller":"rejoinclient/client.go:65","msg":"Starting RejoinClient"}
|
||||
{"level":"INFO","ts":"2022-09-08T10:21:53Z","logger":"recoveryServer","caller":"recoveryserver/server.go:59","msg":"Starting RecoveryServer"}
|
||||
```
|
||||
|
||||
The node will then try to connect to the [*JoinService*](../architecture/microservices.md#joinservice) and obtain the decryption key.
|
||||
If this fails due to an unhealthy control plane, you will see log messages similar to the following:
|
||||
|
||||
```json
|
||||
{"level":"INFO","ts":"2022-09-08T10:21:53Z","logger":"rejoinClient","caller":"rejoinclient/client.go:77","msg":"Received list with JoinService endpoints","endpoints":["192.168.178.4:30090","192.168.178.2:30090"]}
|
||||
{"level":"INFO","ts":"2022-09-08T10:21:53Z","logger":"rejoinClient","caller":"rejoinclient/client.go:96","msg":"Requesting rejoin ticket","endpoint":"192.168.178.4:30090"}
|
||||
{"level":"WARN","ts":"2022-09-08T10:21:53Z","logger":"rejoinClient","caller":"rejoinclient/client.go:101","msg":"Failed to rejoin on endpoint","error":"rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial tcp 192.168.178.4:30090: connect: connection refused\"","endpoint":"192.168.178.4:30090"}
|
||||
{"level":"INFO","ts":"2022-09-08T10:21:53Z","logger":"rejoinClient","caller":"rejoinclient/client.go:96","msg":"Requesting rejoin ticket","endpoint":"192.168.178.2:30090"}
|
||||
{"level":"WARN","ts":"2022-09-08T10:22:13Z","logger":"rejoinClient","caller":"rejoinclient/client.go:101","msg":"Failed to rejoin on endpoint","error":"rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial tcp 192.168.178.2:30090: i/o timeout\"","endpoint":"192.168.178.2:30090"}
|
||||
{"level":"ERROR","ts":"2022-09-08T10:22:13Z","logger":"rejoinClient","caller":"rejoinclient/client.go:110","msg":"Failed to rejoin on all endpoints"}
|
||||
```
|
||||
|
||||
This means that you have to recover the node manually.
|
||||
|
||||
</tabItem>
|
||||
</tabs>
|
||||
|
||||
|
@ -78,6 +78,17 @@ This example shows how to set up a Constellation cluster with the reference IAM
|
||||
|
||||
Optionally, you can prefix the `terraform apply` command with `TF_LOG=INFO` to collect [Terraform logs](https://developer.hashicorp.com/terraform/internals/debugging) while applying the configuration. This may provide helpful output in debugging scenarios.
|
||||
</tabItem>
|
||||
<tabItem value="stackit" label="STACKIT">
|
||||
Initialize the providers and apply the configuration.
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
terraform apply
|
||||
```
|
||||
|
||||
Optionally, you can prefix the `terraform apply` command with `TF_LOG=INFO` to collect [Terraform logs](https://developer.hashicorp.com/terraform/internals/debugging) while applying the configuration. This may provide helpful output in debugging scenarios.
|
||||
</tabItem>
|
||||
|
||||
</tabs>
|
||||
4. Connect to the cluster.
|
||||
|
||||
|
@ -33,6 +33,10 @@ You don't need to verify the Constellation node images. This is done automatical
|
||||
|
||||
## Verify the signature
|
||||
|
||||
:::info
|
||||
This guide assumes Linux on an amd64 processor. The exact steps for other platforms differ slightly.
|
||||
:::
|
||||
|
||||
First, [install the Cosign CLI](https://docs.sigstore.dev/system_config/installation). Next, [download](https://github.com/edgelesssys/constellation/releases) and verify the signature that accompanies your CLI executable, for example:
|
||||
|
||||
```shell-session
|
||||
|
@ -63,6 +63,7 @@ rollout
|
||||
SBOM
|
||||
sigstore
|
||||
SSD
|
||||
STACKIT
|
||||
superset
|
||||
Syft
|
||||
systemd
|
||||
|
4
go.mod
4
go.mod
@ -134,7 +134,7 @@ require (
|
||||
golang.org/x/tools v0.18.0
|
||||
google.golang.org/api v0.165.0
|
||||
google.golang.org/grpc v1.61.1
|
||||
google.golang.org/protobuf v1.32.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm v2.17.0+incompatible
|
||||
helm.sh/helm/v3 v3.14.2
|
||||
@ -300,7 +300,7 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // 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
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -1008,8 +1008,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
4
go.work
4
go.work
@ -1,6 +1,6 @@
|
||||
go 1.22.0
|
||||
go 1.22.1
|
||||
|
||||
toolchain go1.22.0
|
||||
toolchain go1.22.1
|
||||
|
||||
use (
|
||||
.
|
||||
|
@ -46,7 +46,7 @@ require (
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
golang.org/x/term v0.17.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1 // indirect
|
||||
|
@ -813,8 +813,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -68,7 +68,7 @@ b0fc6c55f5989aebf6e71279541206070b32b3b28b708a249bd3bdeaa6c088a4 filesystem-3.1
|
||||
79986f917ef1bae7ca2378b16515ba44c19160f5a5eae4f6b697eda160bc26c1 findutils-4.9.0-3.fc38.x86_64.rpm
|
||||
d5ae6a7d99826a17d163d9846c2705442b5792a7ccacc5169e4986cdf4b6bae2 fuse-common-3.14.1-1.fc38.x86_64.rpm
|
||||
56df47937646df892dad25c6b9ae63d111328febfe86eb93096b8b0a11700b60 fuse-libs-2.9.9-16.fc38.x86_64.rpm
|
||||
1e9e8b6447c2650a306e8d107dbdcdaa4f81d4175012eea0c87846faecd64c70 fuse-overlayfs-1.12-1.fc38.x86_64.rpm
|
||||
088ebe20ac0854c1f216883aa1f6ed8dfc7844807455f4acfef05b7a4b8509db fuse-overlayfs-1.13-1.fc38.x86_64.rpm
|
||||
55ca555fe815bd360b08500889b652f50fe4c56dfafbed0cc459f2362641f1a0 fuse3-3.14.1-1.fc38.x86_64.rpm
|
||||
f54340fec047cc359a6a164a1ce88d0d7ffcd8f7d6334b50dc5b3d234e3a19ac fuse3-libs-3.14.1-1.fc38.x86_64.rpm
|
||||
e607df61803999da46a199d23d4acadb45b290f29b5b644e583c5526d8081178 gawk-5.1.1-5.fc38.x86_64.rpm
|
||||
@ -256,7 +256,7 @@ dea697370ede1848c1a54fdccebf792155d98cbdc5de89e85bbc75ec7c94de8f p11-kit-trust-
|
||||
21c59eeb1ad62c09aadca6a4168f927ff943f82e4f764d589f5acb2ab6efc993 pam-libs-1.5.2-16.fc38.i686.rpm
|
||||
63e970f7b3f8c54e1dff90661c26519f32a4bf7486c40f2dd38d55e40660230e pam-libs-1.5.2-16.fc38.x86_64.rpm
|
||||
8d846f866158409c775656b39e372d59cf224936d29972d3b6d14e40d3b832ca parted-3.5-11.fc38.x86_64.rpm
|
||||
5ab994e5589d48c9e600ef7a42c53653607d0c6455c55f739e07da7c3a483bf6 passt-0^20231230.gf091893-1.fc38.x86_64.rpm
|
||||
7a4cd426505349a948fbc5bcc24545fbdfb7807d525a9c5a41e75dd57b79dccf passt-0^20240220.g1e6f92b-1.fc38.x86_64.rpm
|
||||
43603df046850c4cf067960d8e47998de5c33955b1f865df8d66f20c1b7f676a passwd-0.80-14.fc38.x86_64.rpm
|
||||
f2737b94fa026a56c7a427f8f4221ff379ea4c4c32f2fff9d95a7a7836dcc6c7 pcre2-10.42-1.fc38.1.i686.rpm
|
||||
cb1caf3e9a4ddc8343c0757c7a2730bf5de2b5f0b4c9ee7d928609566f64f010 pcre2-10.42-1.fc38.1.x86_64.rpm
|
||||
@ -341,7 +341,7 @@ cce5fcc8b6b0312caeca04a19494358888b00c125747f5c2d2bd8f006665c730 vim-common-9.1
|
||||
5fa001dbcd0752e75421b2e96aabb73265a48cdd646b02dc947da768147f2be8 vim-data-9.1.113-1.fc38.noarch.rpm
|
||||
545d77bb579a8fb3e87ecd1d5acf616b4b837612f189206171edad73fd4864ab vim-enhanced-9.1.113-1.fc38.x86_64.rpm
|
||||
8743bcb074aed6aa20914b7d0258cd6938e3642fe3550279bb1c66c6300d936a vim-filesystem-9.1.113-1.fc38.noarch.rpm
|
||||
7f8524d182dacd6bef744c11d225dd63a82100350e95fe3ec414e70cf642c1f1 wget-1.21.3-5.fc38.x86_64.rpm
|
||||
a4c8b2a90705fed491f6f7f258904637c18773d323d39e97bf9036260b79a0f6 wget-1.21.4-1.fc38.x86_64.rpm
|
||||
2c8b143f3cb83efa5a31c85bea1da3164ca2dde5e2d75d25115f3e21ef98b4e0 which-2.21-39.fc38.x86_64.rpm
|
||||
84f87df3afabe3de8748f172220107e5a5cbb0f0ef954386ecff6b914604aada whois-nls-5.5.18-1.fc38.noarch.rpm
|
||||
59a7a5a775c196961cdc51fb89440a055295c767a632bfa684760e73650aa9a0 xkeyboard-config-2.38-1.fc38.noarch.rpm
|
||||
|
@ -13,7 +13,7 @@ Seed=0e9a6fe0-68f6-408c-bbeb-136054d20445
|
||||
SourceDateEpoch=0
|
||||
Bootable=yes
|
||||
Bootloader=uki
|
||||
KernelCommandLine=preempt=full rd.shell=0 rd.emergency=reboot loglevel=8 console=ttyS0
|
||||
KernelCommandLine=preempt=full rd.shell=0 rd.emergency=reboot loglevel=8
|
||||
RemoveFiles=/var/log
|
||||
RemoveFiles=/var/cache
|
||||
RemoveFiles=/etc/pki/ca-trust/extracted/java/cacerts
|
||||
|
@ -55,6 +55,7 @@ base_cmdline = "selinux=1 enforcing=0 audit=0"
|
||||
csp_settings = {
|
||||
"aws": {
|
||||
"kernel_command_line_dict": {
|
||||
"console": "ttyS0",
|
||||
"constel.csp": "aws",
|
||||
"idle": "poll",
|
||||
"mitigations": "auto",
|
||||
@ -62,20 +63,21 @@ csp_settings = {
|
||||
},
|
||||
"azure": {
|
||||
"kernel_command_line_dict": {
|
||||
"console": "ttyS0",
|
||||
"constel.csp": "azure",
|
||||
"mitigations": "auto,nosmt",
|
||||
},
|
||||
},
|
||||
"gcp": {
|
||||
"kernel_command_line_dict": {
|
||||
"console": "ttyS0",
|
||||
"constel.csp": "gcp",
|
||||
"mitigations": "auto,nosmt",
|
||||
},
|
||||
},
|
||||
"openstack": {
|
||||
"kernel_command_line": "console=tty0 console=ttyS0",
|
||||
"kernel_command_line": "console=tty0 console=ttyS0 console=ttyS1",
|
||||
"kernel_command_line_dict": {
|
||||
"console": "tty0",
|
||||
"constel.csp": "openstack",
|
||||
"kvm_amd.sev": "1",
|
||||
"mem_encrypt": "on",
|
||||
@ -86,6 +88,7 @@ csp_settings = {
|
||||
"qemu": {
|
||||
"autologin": True,
|
||||
"kernel_command_line_dict": {
|
||||
"console": "ttyS0",
|
||||
"constel.csp": "qemu",
|
||||
"mitigations": "auto,nosmt",
|
||||
},
|
||||
|
@ -16,13 +16,13 @@ package measurements
|
||||
|
||||
// revive:disable:var-naming
|
||||
var (
|
||||
aws_AWSNitroTPM = M{0: {Expected: []byte{0x73, 0x7f, 0x76, 0x7a, 0x12, 0xf5, 0x4e, 0x70, 0xee, 0xcb, 0xc8, 0x68, 0x40, 0x11, 0x32, 0x3a, 0xe2, 0xfe, 0x2d, 0xd9, 0xf9, 0x07, 0x85, 0x57, 0x79, 0x69, 0xd7, 0xa2, 0x01, 0x3e, 0x8c, 0x12}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x82, 0x51, 0xcf, 0x40, 0x53, 0x18, 0x0d, 0x53, 0x64, 0x75, 0x03, 0x45, 0xa5, 0xa8, 0x16, 0xe2, 0x4b, 0x23, 0x40, 0x83, 0x43, 0x83, 0xbd, 0x43, 0x49, 0x8b, 0x8f, 0xb7, 0xc9, 0x4d, 0x57, 0xdd}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x5d, 0x1b, 0xbe, 0xd7, 0xec, 0x13, 0xc8, 0xd5, 0xea, 0x93, 0x71, 0xce, 0x79, 0x02, 0x13, 0xbe, 0x82, 0x5b, 0xed, 0x55, 0x26, 0x77, 0x0a, 0x87, 0x7c, 0x45, 0xdf, 0x76, 0xdd, 0x1b, 0x2a, 0x12}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x8a, 0x2b, 0xe4, 0xe4, 0x71, 0x23, 0xbd, 0xc8, 0x99, 0x0d, 0xbe, 0x36, 0xad, 0x77, 0xee, 0x04, 0xc5, 0x4e, 0x7d, 0x68, 0xc6, 0x1d, 0x86, 0xde, 0x9d, 0x0a, 0xf3, 0x48, 0xe6, 0xdf, 0x60, 0x15}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
aws_AWSSEVSNP = M{0: {Expected: []byte{0x7b, 0x06, 0x8c, 0x0c, 0x3a, 0xc2, 0x9a, 0xfe, 0x26, 0x41, 0x34, 0x53, 0x6b, 0x9b, 0xe2, 0x6f, 0x1d, 0x4c, 0xcd, 0x57, 0x5b, 0x88, 0xd3, 0xc3, 0xce, 0xab, 0xf3, 0x6a, 0xc9, 0x9c, 0x02, 0x78}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x74, 0x17, 0x6b, 0x8a, 0x77, 0xd9, 0x49, 0x1a, 0xd3, 0xe5, 0x62, 0xd2, 0xea, 0xba, 0x5f, 0x85, 0xd7, 0x3d, 0x26, 0x4e, 0x30, 0xaf, 0x78, 0x7e, 0x58, 0x33, 0x47, 0x13, 0x8e, 0x56, 0x23, 0x8a}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x3e, 0xc6, 0xf2, 0xe4, 0xf0, 0x59, 0xee, 0xf7, 0x29, 0xe4, 0xde, 0x5f, 0x70, 0x67, 0x15, 0x8d, 0x1f, 0x10, 0x1d, 0x7d, 0xd1, 0x40, 0x3c, 0x9f, 0x87, 0x48, 0xfb, 0xf5, 0x77, 0xa6, 0x03, 0xbb}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x84, 0xae, 0x81, 0x49, 0x2f, 0x9c, 0x6e, 0x2c, 0x8c, 0x49, 0x39, 0x27, 0x79, 0x7e, 0x85, 0x8d, 0xbc, 0xf1, 0x2f, 0x80, 0xde, 0x43, 0xd0, 0xbb, 0x47, 0xe7, 0xf0, 0x50, 0x3e, 0xa2, 0xa8, 0x6a}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
azure_AzureSEVSNP = M{1: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x4b, 0xdf, 0xb0, 0xb8, 0x91, 0xde, 0x2a, 0xaa, 0xc7, 0x3f, 0x1a, 0xb6, 0x9c, 0xde, 0xb2, 0xed, 0x66, 0x62, 0x29, 0xf5, 0x83, 0x40, 0x9e, 0x95, 0x00, 0xca, 0x21, 0xdb, 0xb1, 0xf7, 0x06, 0x7d}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x3c, 0xb3, 0x7a, 0xfe, 0xeb, 0x1c, 0xb7, 0xf8, 0x98, 0xb5, 0x0d, 0x3b, 0x9d, 0x17, 0xa7, 0x3b, 0x83, 0x61, 0x2d, 0xef, 0xaa, 0x3a, 0xeb, 0x1c, 0xcd, 0x61, 0x99, 0xbf, 0x48, 0x9e, 0x28, 0xd2}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x2c, 0xbe, 0x09, 0x13, 0xac, 0xfb, 0x6f, 0xcf, 0x6d, 0xa9, 0x55, 0xbc, 0x77, 0xf4, 0xed, 0x27, 0x0b, 0xfc, 0x1c, 0xe4, 0xf8, 0x02, 0xd4, 0xc9, 0xf5, 0x37, 0xde, 0x1f, 0x85, 0xa2, 0x66, 0x25}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
azure_AzureTDX = M{1: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x2f, 0xda, 0xe7, 0x93, 0xbe, 0x8d, 0x3d, 0x81, 0xaf, 0x62, 0x5d, 0x37, 0x95, 0x26, 0x37, 0x02, 0x36, 0xe2, 0x22, 0x99, 0x49, 0x36, 0x7a, 0x09, 0x90, 0x1b, 0x4c, 0x6d, 0xf1, 0xfa, 0x43, 0x7e}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x76, 0xcd, 0x4f, 0xe2, 0x88, 0xa6, 0xa5, 0xc0, 0x0f, 0x63, 0x0d, 0x75, 0x0c, 0xe8, 0x24, 0xc0, 0x96, 0x2b, 0xbf, 0xbd, 0x78, 0xda, 0xd9, 0x1b, 0x18, 0x20, 0x4b, 0x2e, 0xf9, 0x00, 0x49, 0xbf}, ValidationOpt: Enforce}, 11: {Expected: []byte{0xf0, 0x93, 0x1f, 0xfc, 0x64, 0x30, 0xff, 0x44, 0xbd, 0xca, 0xe0, 0x50, 0xa9, 0xe2, 0xd6, 0x2a, 0xd2, 0xae, 0x64, 0x08, 0xc1, 0x0e, 0x33, 0x4f, 0x9b, 0xc6, 0x2b, 0xb6, 0xae, 0x88, 0x60, 0x8c}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
aws_AWSNitroTPM = M{0: {Expected: []byte{0x73, 0x7f, 0x76, 0x7a, 0x12, 0xf5, 0x4e, 0x70, 0xee, 0xcb, 0xc8, 0x68, 0x40, 0x11, 0x32, 0x3a, 0xe2, 0xfe, 0x2d, 0xd9, 0xf9, 0x07, 0x85, 0x57, 0x79, 0x69, 0xd7, 0xa2, 0x01, 0x3e, 0x8c, 0x12}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0xb6, 0x86, 0xbc, 0x7c, 0xe9, 0xee, 0x11, 0x3c, 0x4e, 0xe4, 0x66, 0xf2, 0xce, 0x24, 0xdd, 0xef, 0x11, 0x39, 0x75, 0x7e, 0xe2, 0xd3, 0xa7, 0xcc, 0xd3, 0x8c, 0x5e, 0x34, 0x15, 0xb3, 0x60, 0x4e}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xe4, 0x84, 0x0d, 0x74, 0xe5, 0xaa, 0xaf, 0x7a, 0x75, 0x27, 0xce, 0xd7, 0x28, 0xc0, 0xa7, 0x51, 0x24, 0x32, 0x61, 0x06, 0x14, 0xb7, 0x6a, 0xee, 0xc3, 0x43, 0xa6, 0x56, 0x47, 0xc5, 0x41, 0xed}, ValidationOpt: Enforce}, 11: {Expected: []byte{0xfa, 0x60, 0x0e, 0xf1, 0x9b, 0xd8, 0x81, 0x70, 0xa7, 0xa0, 0x34, 0x86, 0x79, 0x35, 0xe0, 0x4d, 0x48, 0xa0, 0xc2, 0x8c, 0xda, 0x9c, 0xa8, 0xbb, 0xdc, 0xce, 0x9b, 0x51, 0x04, 0x7d, 0xca, 0x2c}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
aws_AWSSEVSNP = M{0: {Expected: []byte{0x7b, 0x06, 0x8c, 0x0c, 0x3a, 0xc2, 0x9a, 0xfe, 0x26, 0x41, 0x34, 0x53, 0x6b, 0x9b, 0xe2, 0x6f, 0x1d, 0x4c, 0xcd, 0x57, 0x5b, 0x88, 0xd3, 0xc3, 0xce, 0xab, 0xf3, 0x6a, 0xc9, 0x9c, 0x02, 0x78}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x93, 0x6b, 0x2f, 0xf8, 0x60, 0xa3, 0xfa, 0x97, 0x05, 0x46, 0xe9, 0x8c, 0x43, 0xb6, 0xdd, 0x42, 0x39, 0x34, 0x9d, 0x53, 0xe9, 0x10, 0xba, 0x04, 0x6c, 0xe9, 0x5a, 0x2e, 0x85, 0x9b, 0xbb, 0x2e}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xf3, 0x96, 0x93, 0x03, 0x13, 0xa3, 0x67, 0x8c, 0xf9, 0xc5, 0x1d, 0x89, 0x34, 0xbc, 0xd1, 0xcf, 0xd0, 0xf6, 0x15, 0x56, 0x6c, 0xac, 0x3a, 0xee, 0xba, 0xbd, 0xe9, 0x71, 0x2e, 0x8b, 0xc1, 0xa1}, ValidationOpt: Enforce}, 11: {Expected: []byte{0xc3, 0xa8, 0x62, 0xa2, 0x72, 0x2e, 0xa9, 0x0d, 0x73, 0xf0, 0x51, 0x14, 0x4c, 0x2d, 0x79, 0x76, 0x87, 0x40, 0xb8, 0x45, 0xf5, 0x39, 0xa6, 0xab, 0x0d, 0x62, 0xe2, 0x2c, 0x9f, 0x84, 0x1b, 0x03}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
azure_AzureSEVSNP = M{1: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0xe7, 0x66, 0xf4, 0x6e, 0xd4, 0x3f, 0x14, 0x56, 0x49, 0xee, 0xdb, 0x05, 0xd3, 0xcc, 0xfe, 0xbd, 0x62, 0xee, 0xb8, 0xff, 0x9a, 0xac, 0x93, 0xb0, 0x3a, 0x10, 0x5a, 0x33, 0x9c, 0x41, 0x93, 0xb9}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xd3, 0x01, 0x66, 0x75, 0xb2, 0xf2, 0xf5, 0x48, 0x0b, 0xc4, 0x4a, 0x58, 0xfd, 0xe3, 0x3b, 0x61, 0x08, 0xe3, 0xb4, 0x6c, 0x3e, 0xac, 0x6c, 0x3e, 0x54, 0xd6, 0x6d, 0xb3, 0x50, 0x09, 0xcc, 0xad}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x2b, 0xce, 0x7d, 0x09, 0xec, 0x08, 0xdb, 0xa5, 0x0b, 0xae, 0x74, 0x5d, 0x5a, 0x46, 0xea, 0x3e, 0x61, 0xd4, 0x8e, 0xdb, 0x80, 0x41, 0x63, 0xb4, 0xac, 0xff, 0xf3, 0x56, 0x79, 0xdb, 0x83, 0x6f}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
azure_AzureTDX = M{1: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x77, 0xe4, 0x8c, 0xa5, 0x0d, 0x52, 0x9a, 0x3b, 0x71, 0xfd, 0x73, 0x5a, 0x79, 0x33, 0xcf, 0x5a, 0xe6, 0x19, 0x45, 0x9b, 0x86, 0x80, 0x70, 0x92, 0x81, 0xf6, 0x2c, 0x8b, 0xb4, 0x48, 0xfb, 0x38}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x83, 0x1d, 0x7d, 0x4f, 0xbd, 0x1f, 0x8b, 0xa5, 0xd1, 0x5e, 0x77, 0x58, 0xe7, 0x81, 0xa4, 0x8f, 0xcf, 0xc3, 0xdc, 0x7f, 0x0c, 0xdb, 0xf9, 0x3b, 0xa5, 0x08, 0x6e, 0x89, 0x11, 0xf9, 0xec, 0x4a}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x06, 0xfb, 0x71, 0xdf, 0xc3, 0xba, 0x72, 0xbd, 0x7b, 0xed, 0x9f, 0xa6, 0xa7, 0x44, 0x96, 0x68, 0xcd, 0x5b, 0xee, 0x09, 0x1d, 0x9e, 0x3e, 0x3c, 0x4e, 0xd0, 0xfb, 0x71, 0x6d, 0x90, 0x4f, 0x1d}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
azure_AzureTrustedLaunch M
|
||||
gcp_GCPSEVES = M{1: {Expected: []byte{0x36, 0x95, 0xdc, 0xc5, 0x5e, 0x3a, 0xa3, 0x40, 0x27, 0xc2, 0x77, 0x93, 0xc8, 0x5c, 0x72, 0x3c, 0x69, 0x7d, 0x70, 0x8c, 0x42, 0xd1, 0xf7, 0x3b, 0xd6, 0xfa, 0x4f, 0x26, 0x60, 0x8a, 0x5b, 0x24}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0x4b, 0x86, 0x61, 0xc4, 0xa5, 0xcf, 0xf5, 0xab, 0x94, 0x66, 0x89, 0xf9, 0x03, 0xac, 0x96, 0xda, 0x3f, 0x39, 0xbb, 0xf6, 0xa0, 0xf6, 0x9a, 0x6d, 0x56, 0x01, 0xd4, 0x21, 0xbd, 0xb2, 0x03, 0x61}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xfd, 0xce, 0x5f, 0xe7, 0xe9, 0xfa, 0x32, 0xb6, 0x38, 0xc9, 0x96, 0x6a, 0x7b, 0x33, 0xbb, 0x39, 0x83, 0xa3, 0x78, 0x69, 0x2a, 0xa7, 0x4e, 0x91, 0xfd, 0x8c, 0xc7, 0x96, 0xa2, 0x46, 0xc5, 0x33}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x0d, 0xbc, 0xbe, 0x7f, 0x07, 0x46, 0xa1, 0x83, 0x4f, 0xfa, 0x4d, 0x88, 0xdb, 0xee, 0xa1, 0xb8, 0x0c, 0x9a, 0x6b, 0xac, 0x1f, 0x06, 0x88, 0x41, 0xb9, 0x69, 0x0a, 0xdb, 0xfe, 0xab, 0x09, 0x28}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
openstack_QEMUVTPM = M{4: {Expected: []byte{0x85, 0x68, 0x3d, 0xec, 0xd8, 0x84, 0x84, 0xeb, 0x89, 0x71, 0x53, 0x1e, 0x33, 0x84, 0x27, 0x40, 0x70, 0x26, 0xce, 0x88, 0xd1, 0x6e, 0x75, 0x24, 0xcd, 0xb3, 0xbc, 0x7a, 0x7e, 0x53, 0x45, 0x7c}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xa2, 0x83, 0x80, 0x53, 0x68, 0xff, 0x7f, 0xc3, 0xe1, 0x9d, 0xdf, 0x49, 0x6d, 0x7a, 0x8c, 0x42, 0x53, 0x02, 0xc4, 0x5d, 0x2e, 0xd4, 0x2d, 0x3e, 0x85, 0xc8, 0x67, 0xf6, 0x6e, 0x88, 0x29, 0x1c}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x52, 0x9b, 0x1e, 0x7a, 0x81, 0xb5, 0xca, 0x2f, 0x12, 0x56, 0x7d, 0x73, 0xe5, 0x0f, 0xf0, 0x83, 0x77, 0x1f, 0x2e, 0x54, 0x1d, 0x19, 0xd7, 0x99, 0xfd, 0xb3, 0xc6, 0x87, 0xf6, 0x33, 0x2f, 0x7c}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
gcp_GCPSEVES = M{1: {Expected: []byte{0x36, 0x95, 0xdc, 0xc5, 0x5e, 0x3a, 0xa3, 0x40, 0x27, 0xc2, 0x77, 0x93, 0xc8, 0x5c, 0x72, 0x3c, 0x69, 0x7d, 0x70, 0x8c, 0x42, 0xd1, 0xf7, 0x3b, 0xd6, 0xfa, 0x4f, 0x26, 0x60, 0x8a, 0x5b, 0x24}, ValidationOpt: WarnOnly}, 2: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 3: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 4: {Expected: []byte{0xb3, 0xc3, 0x6a, 0x88, 0xf7, 0xa3, 0x51, 0x4d, 0x25, 0xc5, 0xcc, 0x2b, 0x2a, 0x05, 0x47, 0xb5, 0xda, 0x76, 0x66, 0x2e, 0xe5, 0x90, 0x11, 0xb5, 0x29, 0xbc, 0xfc, 0x07, 0x62, 0x4b, 0xb9, 0x3f}, ValidationOpt: Enforce}, 6: {Expected: []byte{0x3d, 0x45, 0x8c, 0xfe, 0x55, 0xcc, 0x03, 0xea, 0x1f, 0x44, 0x3f, 0x15, 0x62, 0xbe, 0xec, 0x8d, 0xf5, 0x1c, 0x75, 0xe1, 0x4a, 0x9f, 0xcf, 0x9a, 0x72, 0x34, 0xa1, 0x3f, 0x19, 0x8e, 0x79, 0x69}, ValidationOpt: WarnOnly}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x8a, 0x97, 0x88, 0x17, 0x3f, 0x55, 0x40, 0x9d, 0x5f, 0x6e, 0x90, 0xee, 0x0f, 0x9a, 0x22, 0x7a, 0xa6, 0x2f, 0xf7, 0xbc, 0x78, 0xd6, 0xbc, 0x85, 0x28, 0xd9, 0x75, 0xe7, 0x94, 0x28, 0x95, 0x85}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x52, 0xca, 0xc5, 0xa6, 0x44, 0xb9, 0xf0, 0xc7, 0x5b, 0x32, 0x42, 0x03, 0x1f, 0x7c, 0x80, 0x03, 0xdb, 0xdc, 0x3c, 0xc7, 0xc4, 0x0b, 0xd3, 0x83, 0x8a, 0xef, 0x0c, 0x85, 0x7b, 0xbf, 0xf1, 0x8d}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
openstack_QEMUVTPM = M{4: {Expected: []byte{0xc5, 0x70, 0xa4, 0xff, 0xba, 0xc6, 0x7b, 0x93, 0x48, 0x88, 0x6b, 0x11, 0xe2, 0x80, 0xa5, 0xf0, 0x43, 0xc1, 0x2f, 0xba, 0x8e, 0xb3, 0xfb, 0x36, 0x6d, 0x71, 0x8f, 0x7c, 0x85, 0x97, 0x44, 0x98}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0x45, 0x06, 0xb3, 0xfb, 0xcb, 0xd3, 0x27, 0x21, 0x2a, 0xb6, 0x52, 0xf8, 0x68, 0x65, 0x69, 0x88, 0x6e, 0xb5, 0x83, 0xd3, 0x97, 0xe0, 0x6a, 0x77, 0xa8, 0xdf, 0xeb, 0xb8, 0xe0, 0xa4, 0x01, 0xe2}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x7c, 0xd6, 0xa4, 0xe5, 0x2c, 0x00, 0x42, 0x46, 0x3f, 0xe4, 0xd6, 0x07, 0x21, 0xc0, 0xc2, 0xff, 0xb4, 0xcd, 0xc1, 0xf9, 0x3d, 0xad, 0xd8, 0x8d, 0x48, 0xc2, 0x71, 0xef, 0xcc, 0x5f, 0x13, 0x14}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 14: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: WarnOnly}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
qemu_QEMUTDX M
|
||||
qemu_QEMUVTPM = M{4: {Expected: []byte{0xa5, 0xb1, 0x6b, 0x64, 0x66, 0x8c, 0x31, 0x59, 0xc6, 0xbd, 0x69, 0x9b, 0x4d, 0x26, 0x77, 0x0e, 0xf0, 0xbf, 0xe9, 0xdf, 0x32, 0x2d, 0xa6, 0x8c, 0x11, 0x1d, 0x9c, 0x9e, 0x89, 0x0e, 0x7b, 0x93}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xfc, 0x4b, 0xe9, 0x6f, 0xd0, 0x3e, 0x90, 0x6e, 0xdc, 0x50, 0xbc, 0x6c, 0xdd, 0x0d, 0x6d, 0xe2, 0x9f, 0x7b, 0xcb, 0xbc, 0x8a, 0xd2, 0x42, 0x3a, 0x0a, 0x04, 0xcd, 0x3b, 0xb6, 0xf2, 0x3d, 0x49}, ValidationOpt: Enforce}, 11: {Expected: []byte{0xd8, 0xa6, 0x91, 0x12, 0x82, 0x4b, 0x98, 0xd3, 0x85, 0x7f, 0xa0, 0x85, 0x49, 0x4a, 0x76, 0x86, 0xa0, 0xfc, 0xa8, 0x07, 0x14, 0x88, 0xc1, 0x39, 0x3f, 0x20, 0x34, 0x48, 0x42, 0x12, 0xf0, 0x84}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
qemu_QEMUVTPM = M{4: {Expected: []byte{0xd7, 0x4d, 0x99, 0xcd, 0x10, 0xb3, 0xf6, 0x43, 0xd2, 0x91, 0xff, 0x6d, 0x88, 0x88, 0xe2, 0xe4, 0xc5, 0x5e, 0x6d, 0x48, 0xc8, 0x7a, 0xde, 0xac, 0xfb, 0xd3, 0xf5, 0x51, 0x3e, 0xb8, 0x2b, 0x9e}, ValidationOpt: Enforce}, 8: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 9: {Expected: []byte{0xea, 0x05, 0xc1, 0x74, 0x83, 0x05, 0x0e, 0x73, 0x63, 0x73, 0x77, 0x6d, 0xa6, 0x2b, 0xec, 0x0b, 0x3c, 0x69, 0x03, 0x22, 0x10, 0xd3, 0xaa, 0x9f, 0xe3, 0x3a, 0xa4, 0x0d, 0x5f, 0x37, 0x2c, 0x21}, ValidationOpt: Enforce}, 11: {Expected: []byte{0x91, 0xe2, 0x79, 0xac, 0x19, 0x51, 0x61, 0x6d, 0x0d, 0xac, 0x0b, 0xe4, 0x05, 0x20, 0x66, 0x5b, 0xb0, 0xe5, 0x1d, 0xb5, 0x94, 0xd9, 0x47, 0x41, 0xcf, 0x3f, 0x0e, 0x2e, 0x1e, 0xf1, 0x30, 0x43}, ValidationOpt: Enforce}, 12: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 13: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}, 15: {Expected: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ValidationOpt: Enforce}}
|
||||
)
|
||||
|
15
internal/cloud/openstack/clouds/BUILD.bazel
Normal file
15
internal/cloud/openstack/clouds/BUILD.bazel
Normal file
@ -0,0 +1,15 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "clouds",
|
||||
srcs = [
|
||||
"clouds.go",
|
||||
"read.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/cloud/openstack/clouds",
|
||||
visibility = ["//:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/file",
|
||||
"@com_github_mitchellh_go_homedir//:go-homedir",
|
||||
],
|
||||
)
|
193
internal/cloud/openstack/clouds/LICENSE
Normal file
193
internal/cloud/openstack/clouds/LICENSE
Normal file
@ -0,0 +1,193 @@
|
||||
Copyright 2012-2013 Rackspace, Inc.
|
||||
Copyright Gophercloud authors
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed
|
||||
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations under the License.
|
||||
|
||||
------
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
208
internal/cloud/openstack/clouds/clouds.go
Normal file
208
internal/cloud/openstack/clouds/clouds.go
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
Copyright 2012-2013 Rackspace, Inc.
|
||||
Copyright Gophercloud authors
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package clouds
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// Clouds represents a collection of Cloud entries in a clouds.yaml file.
|
||||
type Clouds struct {
|
||||
Clouds map[string]Cloud `yaml:"clouds" json:"clouds"`
|
||||
}
|
||||
|
||||
// Cloud represents an entry in a clouds.yaml/public-clouds.yaml/secure.yaml file.
|
||||
type Cloud struct {
|
||||
Cloud string `yaml:"cloud,omitempty" json:"cloud,omitempty"`
|
||||
Profile string `yaml:"profile,omitempty" json:"profile,omitempty"`
|
||||
AuthInfo *AuthInfo `yaml:"auth,omitempty" json:"auth,omitempty"`
|
||||
AuthType AuthType `yaml:"auth_type,omitempty" json:"auth_type,omitempty"`
|
||||
RegionName string `yaml:"region_name,omitempty" json:"region_name,omitempty"`
|
||||
Regions []Region `yaml:"regions,omitempty" json:"regions,omitempty"`
|
||||
|
||||
// EndpointType and Interface both specify whether to use the public, internal,
|
||||
// or admin interface of a service. They should be considered synonymous, but
|
||||
// EndpointType will take precedence when both are specified.
|
||||
EndpointType string `yaml:"endpoint_type,omitempty" json:"endpoint_type,omitempty"`
|
||||
Interface string `yaml:"interface,omitempty" json:"interface,omitempty"`
|
||||
|
||||
// API Version overrides.
|
||||
IdentityAPIVersion string `yaml:"identity_api_version,omitempty" json:"identity_api_version,omitempty"`
|
||||
VolumeAPIVersion string `yaml:"volume_api_version,omitempty" json:"volume_api_version,omitempty"`
|
||||
|
||||
// Verify whether or not SSL API requests should be verified.
|
||||
Verify *bool `yaml:"verify,omitempty" json:"verify,omitempty"`
|
||||
|
||||
// CACertFile a path to a CA Cert bundle that can be used as part of
|
||||
// verifying SSL API requests.
|
||||
CACertFile string `yaml:"cacert,omitempty" json:"cacert,omitempty"`
|
||||
|
||||
// ClientCertFile a path to a client certificate to use as part of the SSL
|
||||
// transaction.
|
||||
ClientCertFile string `yaml:"cert,omitempty" json:"cert,omitempty"`
|
||||
|
||||
// ClientKeyFile a path to a client key to use as part of the SSL
|
||||
// transaction.
|
||||
ClientKeyFile string `yaml:"key,omitempty" json:"key,omitempty"`
|
||||
}
|
||||
|
||||
// AuthInfo represents the auth section of a cloud entry or
|
||||
// auth options entered explicitly in ClientOpts.
|
||||
type AuthInfo struct {
|
||||
// AuthURL is the keystone/identity endpoint URL.
|
||||
AuthURL string `yaml:"auth_url,omitempty" json:"auth_url,omitempty"`
|
||||
|
||||
// Token is a pre-generated authentication token.
|
||||
Token string `yaml:"token,omitempty" json:"token,omitempty"`
|
||||
|
||||
// Username is the username of the user.
|
||||
Username string `yaml:"username,omitempty" json:"username,omitempty"`
|
||||
|
||||
// UserID is the unique ID of a user.
|
||||
UserID string `yaml:"user_id,omitempty" json:"user_id,omitempty"`
|
||||
|
||||
// Password is the password of the user.
|
||||
Password string `yaml:"password,omitempty" json:"password,omitempty"`
|
||||
|
||||
// Application Credential ID to login with.
|
||||
ApplicationCredentialID string `yaml:"application_credential_id,omitempty" json:"application_credential_id,omitempty"`
|
||||
|
||||
// Application Credential name to login with.
|
||||
ApplicationCredentialName string `yaml:"application_credential_name,omitempty" json:"application_credential_name,omitempty"`
|
||||
|
||||
// Application Credential secret to login with.
|
||||
ApplicationCredentialSecret string `yaml:"application_credential_secret,omitempty" json:"application_credential_secret,omitempty"`
|
||||
|
||||
// SystemScope is a system information to scope to.
|
||||
SystemScope string `yaml:"system_scope,omitempty" json:"system_scope,omitempty"`
|
||||
|
||||
// ProjectName is the common/human-readable name of a project.
|
||||
// Users can be scoped to a project.
|
||||
// ProjectName on its own is not enough to ensure a unique scope. It must
|
||||
// also be combined with either a ProjectDomainName or ProjectDomainID.
|
||||
// ProjectName cannot be combined with ProjectID in a scope.
|
||||
ProjectName string `yaml:"project_name,omitempty" json:"project_name,omitempty"`
|
||||
|
||||
// ProjectID is the unique ID of a project.
|
||||
// It can be used to scope a user to a specific project.
|
||||
ProjectID string `yaml:"project_id,omitempty" json:"project_id,omitempty"`
|
||||
|
||||
// UserDomainName is the name of the domain where a user resides.
|
||||
// It is used to identify the source domain of a user.
|
||||
UserDomainName string `yaml:"user_domain_name,omitempty" json:"user_domain_name,omitempty"`
|
||||
|
||||
// UserDomainID is the unique ID of the domain where a user resides.
|
||||
// It is used to identify the source domain of a user.
|
||||
UserDomainID string `yaml:"user_domain_id,omitempty" json:"user_domain_id,omitempty"`
|
||||
|
||||
// ProjectDomainName is the name of the domain where a project resides.
|
||||
// It is used to identify the source domain of a project.
|
||||
// ProjectDomainName can be used in addition to a ProjectName when scoping
|
||||
// a user to a specific project.
|
||||
ProjectDomainName string `yaml:"project_domain_name,omitempty" json:"project_domain_name,omitempty"`
|
||||
|
||||
// ProjectDomainID is the name of the domain where a project resides.
|
||||
// It is used to identify the source domain of a project.
|
||||
// ProjectDomainID can be used in addition to a ProjectName when scoping
|
||||
// a user to a specific project.
|
||||
ProjectDomainID string `yaml:"project_domain_id,omitempty" json:"project_domain_id,omitempty"`
|
||||
|
||||
// DomainName is the name of a domain which can be used to identify the
|
||||
// source domain of either a user or a project.
|
||||
// If UserDomainName and ProjectDomainName are not specified, then DomainName
|
||||
// is used as a default choice.
|
||||
// It can also be used be used to specify a domain-only scope.
|
||||
DomainName string `yaml:"domain_name,omitempty" json:"domain_name,omitempty"`
|
||||
|
||||
// DomainID is the unique ID of a domain which can be used to identify the
|
||||
// source domain of eitehr a user or a project.
|
||||
// If UserDomainID and ProjectDomainID are not specified, then DomainID is
|
||||
// used as a default choice.
|
||||
// It can also be used be used to specify a domain-only scope.
|
||||
DomainID string `yaml:"domain_id,omitempty" json:"domain_id,omitempty"`
|
||||
|
||||
// DefaultDomain is the domain ID to fall back on if no other domain has
|
||||
// been specified and a domain is required for scope.
|
||||
DefaultDomain string `yaml:"default_domain,omitempty" json:"default_domain,omitempty"`
|
||||
|
||||
// AllowReauth should be set to true if you grant permission for Gophercloud to
|
||||
// cache your credentials in memory, and to allow Gophercloud to attempt to
|
||||
// re-authenticate automatically if/when your token expires. If you set it to
|
||||
// false, it will not cache these settings, but re-authentication will not be
|
||||
// possible. This setting defaults to false.
|
||||
AllowReauth bool `yaml:"allow_reauth,omitempty" json:"allow_reauth,omitempty"`
|
||||
}
|
||||
|
||||
// Region represents a region included as part of cloud in clouds.yaml
|
||||
// According to Python-based openstacksdk, this can be either a struct (as defined)
|
||||
// or a plain string. Custom unmarshallers handle both cases.
|
||||
type Region struct {
|
||||
Name string `yaml:"name,omitempty" json:"name,omitempty"`
|
||||
Values Cloud `yaml:"values,omitempty" json:"values,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON handles either a plain string acting as the Name property or
|
||||
// a struct, mimicking the Python-based openstacksdk.
|
||||
func (r *Region) UnmarshalJSON(data []byte) error {
|
||||
var name string
|
||||
if err := json.Unmarshal(data, &name); err == nil {
|
||||
r.Name = name
|
||||
return nil
|
||||
}
|
||||
|
||||
type region Region
|
||||
var tmp region
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Name = tmp.Name
|
||||
r.Values = tmp.Values
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML handles either a plain string acting as the Name property or
|
||||
// a struct, mimicking the Python-based openstacksdk.
|
||||
func (r *Region) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var name string
|
||||
if err := unmarshal(&name); err == nil {
|
||||
r.Name = name
|
||||
return nil
|
||||
}
|
||||
|
||||
type region Region
|
||||
var tmp region
|
||||
if err := unmarshal(&tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Name = tmp.Name
|
||||
r.Values = tmp.Values
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AuthType respresents a valid method of authentication.
|
||||
type AuthType string
|
||||
|
||||
const (
|
||||
// AuthPassword defines an unknown version of the password.
|
||||
AuthPassword AuthType = "password"
|
||||
// AuthToken defined an unknown version of the token.
|
||||
AuthToken AuthType = "token"
|
||||
|
||||
// AuthV2Password defines version 2 of the password.
|
||||
AuthV2Password AuthType = "v2password"
|
||||
// AuthV2Token defines version 2 of the token.
|
||||
AuthV2Token AuthType = "v2token"
|
||||
|
||||
// AuthV3Password defines version 3 of the password.
|
||||
AuthV3Password AuthType = "v3password"
|
||||
// AuthV3Token defines version 3 of the token.
|
||||
AuthV3Token AuthType = "v3token"
|
||||
|
||||
// AuthV3ApplicationCredential defines version 3 of the application credential.
|
||||
AuthV3ApplicationCredential AuthType = "v3applicationcredential"
|
||||
)
|
59
internal/cloud/openstack/clouds/read.go
Normal file
59
internal/cloud/openstack/clouds/read.go
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package clouds
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
)
|
||||
|
||||
// ReadCloudsYAML reads a clouds.yaml file and returns its contents.
|
||||
func ReadCloudsYAML(fileHandler file.Handler, path string) (Clouds, error) {
|
||||
// Order of operations as performed by the OpenStack CLI:
|
||||
|
||||
// Define a search path for clouds.yaml:
|
||||
// 1. If OS_CLIENT_CONFIG_FILE is set, use it as search path
|
||||
// 2. Otherwise, use the following paths:
|
||||
// - current directory
|
||||
// - `openstack` directory under standard user config directory (e.g. ~/.config/openstack)
|
||||
// - /etc/openstack (Unix only)
|
||||
|
||||
var searchPaths []string
|
||||
if path != "" {
|
||||
expanded, err := homedir.Expand(path)
|
||||
if err == nil {
|
||||
searchPaths = append(searchPaths, expanded)
|
||||
} else {
|
||||
searchPaths = append(searchPaths, path)
|
||||
}
|
||||
} else if osClientConfigFile := os.Getenv("OS_CLIENT_CONFIG_FILE"); osClientConfigFile != "" {
|
||||
searchPaths = append(searchPaths, filepath.Join(osClientConfigFile, "clouds.yaml"))
|
||||
} else {
|
||||
searchPaths = append(searchPaths, "clouds.yaml")
|
||||
confDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return Clouds{}, fmt.Errorf("getting user config directory: %w", err)
|
||||
}
|
||||
searchPaths = append(searchPaths, filepath.Join(confDir, "openstack", "clouds.yaml"))
|
||||
if os.PathSeparator == '/' {
|
||||
searchPaths = append(searchPaths, "/etc/openstack/clouds.yaml")
|
||||
}
|
||||
}
|
||||
|
||||
var cloudsYAML Clouds
|
||||
for _, path := range searchPaths {
|
||||
if err := fileHandler.ReadYAML(path, &cloudsYAML); err == nil {
|
||||
return cloudsYAML, nil
|
||||
}
|
||||
}
|
||||
|
||||
return Clouds{}, fmt.Errorf("clouds.yaml not found in search paths: %v", searchPaths)
|
||||
}
|
@ -23,6 +23,7 @@ import (
|
||||
|
||||
const (
|
||||
imdsMetaDataURL = "http://169.254.169.254/openstack/2018-08-27/meta_data.json"
|
||||
imdsUserDataURL = "http://169.254.169.254/openstack/2018-08-27/user_data"
|
||||
ec2ImdsBaseURL = "http://169.254.169.254/1.0/meta-data"
|
||||
maxCacheAge = 12 * time.Hour
|
||||
)
|
||||
@ -33,6 +34,7 @@ type imdsClient struct {
|
||||
vpcIPCache string
|
||||
vpcIPCacheTime time.Time
|
||||
cache metadataResponse
|
||||
userDataCache userDataResponse
|
||||
cacheTime time.Time
|
||||
}
|
||||
|
||||
@ -129,73 +131,73 @@ func (c *imdsClient) role(ctx context.Context) (role.Role, error) {
|
||||
}
|
||||
|
||||
func (c *imdsClient) loadBalancerEndpoint(ctx context.Context) (string, error) {
|
||||
if c.timeForUpdate(c.cacheTime) || c.cache.Tags.LoadBalancerEndpoint == "" {
|
||||
if c.timeForUpdate(c.cacheTime) || c.userDataCache.LoadBalancerEndpoint == "" {
|
||||
if err := c.update(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if c.cache.Tags.LoadBalancerEndpoint == "" {
|
||||
if c.userDataCache.LoadBalancerEndpoint == "" {
|
||||
return "", errors.New("unable to get load balancer endpoint")
|
||||
}
|
||||
|
||||
return c.cache.Tags.LoadBalancerEndpoint, nil
|
||||
return c.userDataCache.LoadBalancerEndpoint, nil
|
||||
}
|
||||
|
||||
func (c *imdsClient) authURL(ctx context.Context) (string, error) {
|
||||
if c.timeForUpdate(c.cacheTime) || c.cache.Tags.AuthURL == "" {
|
||||
if c.timeForUpdate(c.cacheTime) || c.userDataCache.AuthURL == "" {
|
||||
if err := c.update(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if c.cache.Tags.AuthURL == "" {
|
||||
if c.userDataCache.AuthURL == "" {
|
||||
return "", errors.New("unable to get auth url")
|
||||
}
|
||||
|
||||
return c.cache.Tags.AuthURL, nil
|
||||
return c.userDataCache.AuthURL, nil
|
||||
}
|
||||
|
||||
func (c *imdsClient) userDomainName(ctx context.Context) (string, error) {
|
||||
if c.timeForUpdate(c.cacheTime) || c.cache.Tags.UserDomainName == "" {
|
||||
if c.timeForUpdate(c.cacheTime) || c.userDataCache.UserDomainName == "" {
|
||||
if err := c.update(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if c.cache.Tags.UserDomainName == "" {
|
||||
if c.userDataCache.UserDomainName == "" {
|
||||
return "", errors.New("unable to get user domain name")
|
||||
}
|
||||
|
||||
return c.cache.Tags.UserDomainName, nil
|
||||
return c.userDataCache.UserDomainName, nil
|
||||
}
|
||||
|
||||
func (c *imdsClient) username(ctx context.Context) (string, error) {
|
||||
if c.timeForUpdate(c.cacheTime) || c.cache.Tags.Username == "" {
|
||||
if c.timeForUpdate(c.cacheTime) || c.userDataCache.Username == "" {
|
||||
if err := c.update(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if c.cache.Tags.Username == "" {
|
||||
if c.userDataCache.Username == "" {
|
||||
return "", errors.New("unable to get token name")
|
||||
}
|
||||
|
||||
return c.cache.Tags.Username, nil
|
||||
return c.userDataCache.Username, nil
|
||||
}
|
||||
|
||||
func (c *imdsClient) password(ctx context.Context) (string, error) {
|
||||
if c.timeForUpdate(c.cacheTime) || c.cache.Tags.Password == "" {
|
||||
if c.timeForUpdate(c.cacheTime) || c.userDataCache.Password == "" {
|
||||
if err := c.update(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if c.cache.Tags.Password == "" {
|
||||
if c.userDataCache.Password == "" {
|
||||
return "", errors.New("unable to get token password")
|
||||
}
|
||||
|
||||
return c.cache.Tags.Password, nil
|
||||
return c.userDataCache.Password, nil
|
||||
}
|
||||
|
||||
// timeForUpdate checks whether an update is needed due to cache age.
|
||||
@ -203,18 +205,41 @@ func (c *imdsClient) timeForUpdate(t time.Time) bool {
|
||||
return time.Since(t) > maxCacheAge
|
||||
}
|
||||
|
||||
// update updates instance metadata from the azure imds API.
|
||||
func (c *imdsClient) update(ctx context.Context) error {
|
||||
if err := c.updateInstanceMetadata(ctx); err != nil {
|
||||
return fmt.Errorf("updating instance metadata: %w", err)
|
||||
}
|
||||
if err := c.updateUserData(ctx); err != nil {
|
||||
return fmt.Errorf("updating user data: %w", err)
|
||||
}
|
||||
c.cacheTime = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
// update updates instance metadata from the azure imds API.
|
||||
func (c *imdsClient) updateInstanceMetadata(ctx context.Context) error {
|
||||
resp, err := httpGet(ctx, c.client, imdsMetaDataURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var metadataResp metadataResponse
|
||||
if err := json.Unmarshal(resp, &metadataResp); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("unmarshalling IMDS metadata response %q: %w", resp, err)
|
||||
}
|
||||
c.cache = metadataResp
|
||||
c.cacheTime = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *imdsClient) updateUserData(ctx context.Context) error {
|
||||
resp, err := httpGet(ctx, c.client, imdsUserDataURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var userdataResp userDataResponse
|
||||
if err := json.Unmarshal(resp, &userdataResp); err != nil {
|
||||
return fmt.Errorf("unmarshalling IMDS user_data response %q: %w", resp, err)
|
||||
}
|
||||
c.userDataCache = userdataResp
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -244,7 +269,10 @@ func httpGet(ctx context.Context, c httpClient, url string) ([]byte, error) {
|
||||
}
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("querying the OpenStack IMDS api failed for %q: %w", url, err)
|
||||
}
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return nil, fmt.Errorf("IMDS api might be broken for this server. Recreate the cluster if this issue persists. Querying the OpenStack IMDS api failed for %q with error code %d", url, resp.StatusCode)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return io.ReadAll(resp.Body)
|
||||
@ -259,9 +287,12 @@ type metadataResponse struct {
|
||||
}
|
||||
|
||||
type metadataTags struct {
|
||||
InitSecretHash string `json:"constellation-init-secret-hash,omitempty"`
|
||||
Role string `json:"constellation-role,omitempty"`
|
||||
UID string `json:"constellation-uid,omitempty"`
|
||||
InitSecretHash string `json:"constellation-init-secret-hash,omitempty"`
|
||||
Role string `json:"constellation-role,omitempty"`
|
||||
UID string `json:"constellation-uid,omitempty"`
|
||||
}
|
||||
|
||||
type userDataResponse struct {
|
||||
AuthURL string `json:"openstack-auth-url,omitempty"`
|
||||
UserDomainName string `json:"openstack-user-domain-name,omitempty"`
|
||||
Username string `json:"openstack-username,omitempty"`
|
||||
|
@ -26,7 +26,7 @@ func TestProviderID(t *testing.T) {
|
||||
someErr := errors.New("failed")
|
||||
|
||||
type testCase struct {
|
||||
cache metadataResponse
|
||||
cache any
|
||||
cacheTime time.Time
|
||||
newClient httpClientJSONCreateFunc
|
||||
wantResult string
|
||||
@ -34,7 +34,7 @@ func TestProviderID(t *testing.T) {
|
||||
wantErr bool
|
||||
}
|
||||
|
||||
newTestCases := func(mResp1, mResp2 metadataResponse, expect1, expect2 string) map[string]testCase {
|
||||
newTestCases := func(mResp1, mResp2 any, expect1, expect2 string) map[string]testCase {
|
||||
return map[string]testCase{
|
||||
"cached": {
|
||||
cache: mResp1,
|
||||
@ -43,30 +43,30 @@ func TestProviderID(t *testing.T) {
|
||||
wantCall: false,
|
||||
},
|
||||
"from http": {
|
||||
newClient: newStubHTTPClientJSONFunc(mResp1, nil),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp1, 200, nil),
|
||||
wantResult: expect1,
|
||||
wantCall: true,
|
||||
},
|
||||
"cache outdated": {
|
||||
cache: mResp1,
|
||||
cacheTime: time.Now().AddDate(0, 0, -1),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp2, nil),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp2, 200, nil),
|
||||
wantResult: expect2,
|
||||
wantCall: true,
|
||||
},
|
||||
"cache empty": {
|
||||
cacheTime: time.Now(),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp1, nil),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp1, 200, nil),
|
||||
wantResult: expect1,
|
||||
wantCall: true,
|
||||
},
|
||||
"http error": {
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, someErr),
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 200, someErr),
|
||||
wantCall: true,
|
||||
wantErr: true,
|
||||
},
|
||||
"http empty response": {
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, nil),
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 200, nil),
|
||||
wantCall: true,
|
||||
wantErr: true,
|
||||
},
|
||||
@ -120,32 +120,32 @@ func TestProviderID(t *testing.T) {
|
||||
"authURL": {
|
||||
method: (*imdsClient).authURL,
|
||||
testCases: newTestCases(
|
||||
metadataResponse{Tags: metadataTags{AuthURL: "authURL1"}},
|
||||
metadataResponse{Tags: metadataTags{AuthURL: "authURL2"}},
|
||||
userDataResponse{AuthURL: "authURL1"},
|
||||
userDataResponse{AuthURL: "authURL2"},
|
||||
"authURL1", "authURL2",
|
||||
),
|
||||
},
|
||||
"userDomainName": {
|
||||
method: (*imdsClient).userDomainName,
|
||||
testCases: newTestCases(
|
||||
metadataResponse{Tags: metadataTags{UserDomainName: "userDomainName1"}},
|
||||
metadataResponse{Tags: metadataTags{UserDomainName: "userDomainName2"}},
|
||||
userDataResponse{UserDomainName: "userDomainName1"},
|
||||
userDataResponse{UserDomainName: "userDomainName2"},
|
||||
"userDomainName1", "userDomainName2",
|
||||
),
|
||||
},
|
||||
"username": {
|
||||
method: (*imdsClient).username,
|
||||
testCases: newTestCases(
|
||||
metadataResponse{Tags: metadataTags{Username: "username1"}},
|
||||
metadataResponse{Tags: metadataTags{Username: "username2"}},
|
||||
userDataResponse{Username: "username1"},
|
||||
userDataResponse{Username: "username2"},
|
||||
"username1", "username2",
|
||||
),
|
||||
},
|
||||
"password": {
|
||||
method: (*imdsClient).password,
|
||||
testCases: newTestCases(
|
||||
metadataResponse{Tags: metadataTags{Password: "password1"}},
|
||||
metadataResponse{Tags: metadataTags{Password: "password2"}},
|
||||
userDataResponse{Password: "password1"},
|
||||
userDataResponse{Password: "password2"},
|
||||
"password1", "password2",
|
||||
),
|
||||
},
|
||||
@ -162,10 +162,18 @@ func TestProviderID(t *testing.T) {
|
||||
if tc.newClient != nil {
|
||||
client = tc.newClient(require)
|
||||
}
|
||||
var cache metadataResponse
|
||||
var userDataCache userDataResponse
|
||||
if _, ok := tc.cache.(metadataResponse); ok {
|
||||
cache = tc.cache.(metadataResponse)
|
||||
} else if _, ok := tc.cache.(userDataResponse); ok {
|
||||
userDataCache = tc.cache.(userDataResponse)
|
||||
}
|
||||
imds := &imdsClient{
|
||||
client: client,
|
||||
cache: tc.cache,
|
||||
cacheTime: tc.cacheTime,
|
||||
client: client,
|
||||
cache: cache,
|
||||
userDataCache: userDataCache,
|
||||
cacheTime: tc.cacheTime,
|
||||
}
|
||||
|
||||
result, err := tu.method(imds, context.Background())
|
||||
@ -207,30 +215,35 @@ func TestRole(t *testing.T) {
|
||||
wantCall: false,
|
||||
},
|
||||
"from http": {
|
||||
newClient: newStubHTTPClientJSONFunc(mResp1, nil),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp1, 200, nil),
|
||||
wantResult: expect1,
|
||||
wantCall: true,
|
||||
},
|
||||
"cache outdated": {
|
||||
cache: mResp1,
|
||||
cacheTime: time.Now().AddDate(0, 0, -1),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp2, nil),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp2, 200, nil),
|
||||
wantResult: expect2,
|
||||
wantCall: true,
|
||||
},
|
||||
"cache empty": {
|
||||
cacheTime: time.Now(),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp1, nil),
|
||||
newClient: newStubHTTPClientJSONFunc(mResp1, 200, nil),
|
||||
wantResult: expect1,
|
||||
wantCall: true,
|
||||
},
|
||||
"http error": {
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, someErr),
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 200, someErr),
|
||||
wantCall: true,
|
||||
wantErr: true,
|
||||
},
|
||||
"http status code 500": {
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 500, nil),
|
||||
wantCall: true,
|
||||
wantErr: true,
|
||||
},
|
||||
"http empty response": {
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, nil),
|
||||
newClient: newStubHTTPClientJSONFunc(metadataResponse{}, 200, nil),
|
||||
wantCall: true,
|
||||
wantErr: true,
|
||||
},
|
||||
@ -368,15 +381,17 @@ type httpClientJSONCreateFunc func(r *require.Assertions) *stubHTTPClientJSON
|
||||
|
||||
type stubHTTPClientJSON struct {
|
||||
require *require.Assertions
|
||||
response metadataResponse
|
||||
response any
|
||||
code int
|
||||
err error
|
||||
called bool
|
||||
}
|
||||
|
||||
func newStubHTTPClientJSONFunc(response metadataResponse, err error) httpClientJSONCreateFunc {
|
||||
func newStubHTTPClientJSONFunc(response any, statusCode int, err error) httpClientJSONCreateFunc {
|
||||
return func(r *require.Assertions) *stubHTTPClientJSON {
|
||||
return &stubHTTPClientJSON{
|
||||
response: response,
|
||||
code: statusCode,
|
||||
err: err,
|
||||
require: r,
|
||||
}
|
||||
@ -387,16 +402,26 @@ func (c *stubHTTPClientJSON) Do(_ *http.Request) (*http.Response, error) {
|
||||
c.called = true
|
||||
body, err := json.Marshal(c.response)
|
||||
c.require.NoError(err)
|
||||
return &http.Response{Body: io.NopCloser(bytes.NewReader(body))}, c.err
|
||||
code := 200
|
||||
if c.code != 0 {
|
||||
code = c.code
|
||||
}
|
||||
return &http.Response{StatusCode: code, Status: http.StatusText(code), Body: io.NopCloser(bytes.NewReader(body))}, c.err
|
||||
}
|
||||
|
||||
type stubHTTPClient struct {
|
||||
response string
|
||||
code int
|
||||
err error
|
||||
called bool
|
||||
}
|
||||
|
||||
func (c *stubHTTPClient) Do(_ *http.Request) (*http.Response, error) {
|
||||
c.called = true
|
||||
return &http.Response{Body: io.NopCloser(strings.NewReader(c.response))}, c.err
|
||||
code := 200
|
||||
if c.code != 0 {
|
||||
code = c.code
|
||||
}
|
||||
|
||||
return &http.Response{StatusCode: code, Status: http.StatusText(code), Body: io.NopCloser(strings.NewReader(c.response))}, c.err
|
||||
}
|
||||
|
@ -28,14 +28,14 @@ const (
|
||||
microversion = "2.42"
|
||||
)
|
||||
|
||||
// Cloud is the metadata client for OpenStack.
|
||||
type Cloud struct {
|
||||
// MetadataClient is the metadata client for OpenStack.
|
||||
type MetadataClient struct {
|
||||
api serversAPI
|
||||
imds imdsAPI
|
||||
}
|
||||
|
||||
// New creates a new OpenStack metadata client.
|
||||
func New(ctx context.Context) (*Cloud, error) {
|
||||
func New(ctx context.Context) (*MetadataClient, error) {
|
||||
imds := &imdsClient{client: &http.Client{}}
|
||||
|
||||
authURL, err := imds.authURL(ctx)
|
||||
@ -77,7 +77,7 @@ func New(ctx context.Context) (*Cloud, error) {
|
||||
}
|
||||
networksClient.Microversion = microversion
|
||||
|
||||
return &Cloud{
|
||||
return &MetadataClient{
|
||||
imds: imds,
|
||||
api: &apiClient{
|
||||
servers: serversClient,
|
||||
@ -87,7 +87,7 @@ func New(ctx context.Context) (*Cloud, error) {
|
||||
}
|
||||
|
||||
// Self returns the metadata of the current instance.
|
||||
func (c *Cloud) Self(ctx context.Context) (metadata.InstanceMetadata, error) {
|
||||
func (c *MetadataClient) Self(ctx context.Context) (metadata.InstanceMetadata, error) {
|
||||
name, err := c.imds.name(ctx)
|
||||
if err != nil {
|
||||
return metadata.InstanceMetadata{}, fmt.Errorf("getting name: %w", err)
|
||||
@ -114,7 +114,7 @@ func (c *Cloud) Self(ctx context.Context) (metadata.InstanceMetadata, error) {
|
||||
}
|
||||
|
||||
// List returns the metadata of all instances belonging to the same Constellation cluster.
|
||||
func (c *Cloud) List(ctx context.Context) ([]metadata.InstanceMetadata, error) {
|
||||
func (c *MetadataClient) List(ctx context.Context) ([]metadata.InstanceMetadata, error) {
|
||||
uid, err := c.imds.uid(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting uid: %w", err)
|
||||
@ -211,7 +211,7 @@ func (c *Cloud) List(ctx context.Context) ([]metadata.InstanceMetadata, error) {
|
||||
}
|
||||
|
||||
// UID retrieves the UID of the constellation.
|
||||
func (c *Cloud) UID(ctx context.Context) (string, error) {
|
||||
func (c *MetadataClient) UID(ctx context.Context) (string, error) {
|
||||
uid, err := c.imds.uid(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("retrieving instance UID: %w", err)
|
||||
@ -220,7 +220,7 @@ func (c *Cloud) UID(ctx context.Context) (string, error) {
|
||||
}
|
||||
|
||||
// InitSecretHash retrieves the InitSecretHash of the current instance.
|
||||
func (c *Cloud) InitSecretHash(ctx context.Context) ([]byte, error) {
|
||||
func (c *MetadataClient) InitSecretHash(ctx context.Context) ([]byte, error) {
|
||||
initSecretHash, err := c.imds.initSecretHash(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("retrieving init secret hash: %w", err)
|
||||
@ -232,7 +232,7 @@ func (c *Cloud) InitSecretHash(ctx context.Context) ([]byte, error) {
|
||||
// For OpenStack, the load balancer is a floating ip attached to
|
||||
// a control plane node.
|
||||
// TODO(malt3): Rewrite to use real load balancer once it is available.
|
||||
func (c *Cloud) GetLoadBalancerEndpoint(ctx context.Context) (host, port string, err error) {
|
||||
func (c *MetadataClient) GetLoadBalancerEndpoint(ctx context.Context) (host, port string, err error) {
|
||||
host, err = c.imds.loadBalancerEndpoint(ctx)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("getting load balancer endpoint: %w", err)
|
||||
@ -240,7 +240,7 @@ func (c *Cloud) GetLoadBalancerEndpoint(ctx context.Context) (host, port string,
|
||||
return host, strconv.FormatInt(constants.KubernetesPort, 10), nil
|
||||
}
|
||||
|
||||
func (c *Cloud) getSubnetCIDR(uidTag string) (netip.Prefix, error) {
|
||||
func (c *MetadataClient) getSubnetCIDR(uidTag string) (netip.Prefix, error) {
|
||||
listNetworksOpts := networks.ListOpts{Tags: uidTag}
|
||||
networksPage, err := c.api.ListNetworks(listNetworksOpts).AllPages()
|
||||
if err != nil {
|
||||
@ -285,7 +285,7 @@ func (c *Cloud) getSubnetCIDR(uidTag string) (netip.Prefix, error) {
|
||||
return cidr, nil
|
||||
}
|
||||
|
||||
func (c *Cloud) getServers(uidTag string) ([]servers.Server, error) {
|
||||
func (c *MetadataClient) getServers(uidTag string) ([]servers.Server, error) {
|
||||
listServersOpts := servers.ListOpts{Tags: uidTag}
|
||||
serversPage, err := c.api.ListServers(listServersOpts).AllPages()
|
||||
if err != nil {
|
||||
|
@ -86,7 +86,7 @@ func TestSelf(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
c := &Cloud{imds: tc.imds}
|
||||
c := &MetadataClient{imds: tc.imds}
|
||||
|
||||
got, err := c.Self(context.Background())
|
||||
|
||||
@ -382,7 +382,7 @@ func TestList(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
c := &Cloud{imds: tc.imds, api: tc.api}
|
||||
c := &MetadataClient{imds: tc.imds, api: tc.api}
|
||||
|
||||
got, err := c.List(context.Background())
|
||||
|
||||
@ -416,7 +416,7 @@ func TestUID(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
c := &Cloud{imds: tc.imds}
|
||||
c := &MetadataClient{imds: tc.imds}
|
||||
|
||||
got, err := c.UID(context.Background())
|
||||
|
||||
@ -450,7 +450,7 @@ func TestInitSecretHash(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
c := &Cloud{imds: tc.imds}
|
||||
c := &MetadataClient{imds: tc.imds}
|
||||
|
||||
got, err := c.InitSecretHash(context.Background())
|
||||
|
||||
@ -484,7 +484,7 @@ func TestGetLoadBalancerEndpoint(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
c := &Cloud{imds: tc.imds}
|
||||
c := &MetadataClient{imds: tc.imds}
|
||||
|
||||
got, _, err := c.GetLoadBalancerEndpoint(context.Background())
|
||||
|
||||
|
@ -198,40 +198,22 @@ type OpenStackConfig struct {
|
||||
// OpenStack cloud name to select from "clouds.yaml". Only required if config file for OpenStack is used. Fallback authentication uses environment variables. For details see: https://docs.openstack.org/openstacksdk/latest/user/config/configuration.html.
|
||||
Cloud string `yaml:"cloud"`
|
||||
// description: |
|
||||
// Path to OpenStack "clouds.yaml" file. Only required if automatic detection fails.
|
||||
CloudsYAMLPath string `yaml:"cloudsYAMLPath"`
|
||||
// description: |
|
||||
// Availability zone to place the VMs in. For details see: https://docs.openstack.org/nova/latest/admin/availability-zones.html
|
||||
AvailabilityZone string `yaml:"availabilityZone" validate:"required"`
|
||||
// description: |
|
||||
// Floating IP pool to use for the VMs. For details see: https://docs.openstack.org/ocata/user-guide/cli-manage-ip-addresses.html
|
||||
FloatingIPPoolID string `yaml:"floatingIPPoolID" validate:"required"`
|
||||
// description: |
|
||||
// AuthURL is the OpenStack Identity endpoint to use inside the cluster.
|
||||
AuthURL string `yaml:"authURL" validate:"required"`
|
||||
// description: |
|
||||
// ProjectID is the ID of the OpenStack project where a user resides.
|
||||
ProjectID string `yaml:"projectID" validate:"required"`
|
||||
// description: |
|
||||
// STACKITProjectID is the ID of the STACKIT project where a user resides.
|
||||
// Only used if cloud is "stackit".
|
||||
STACKITProjectID string `yaml:"stackitProjectID"`
|
||||
// description: |
|
||||
// ProjectName is the name of the project where a user resides.
|
||||
ProjectName string `yaml:"projectName" validate:"required"`
|
||||
// description: |
|
||||
// UserDomainName is the name of the domain where a user resides.
|
||||
UserDomainName string `yaml:"userDomainName" validate:"required"`
|
||||
// description: |
|
||||
// ProjectDomainName is the name of the domain where a project resides.
|
||||
ProjectDomainName string `yaml:"projectDomainName" validate:"required"`
|
||||
// description: |
|
||||
// RegionName is the name of the region to use inside the cluster.
|
||||
RegionName string `yaml:"regionName" validate:"required"`
|
||||
// description: |
|
||||
// Username to use inside the cluster.
|
||||
Username string `yaml:"username" validate:"required"`
|
||||
// description: |
|
||||
// Password to use inside the cluster. You can instead use the environment variable "CONSTELL_OS_PASSWORD".
|
||||
Password string `yaml:"password"`
|
||||
// description: |
|
||||
// Deploy Yawol loadbalancer. For details see: https://github.com/stackitcloud/yawol
|
||||
DeployYawolLoadBalancer *bool `yaml:"deployYawolLoadBalancer" validate:"required"`
|
||||
// description: |
|
||||
@ -496,11 +478,6 @@ func New(fileHandler file.Handler, name string, fetcher attestationconfigapi.Fet
|
||||
fmt.Fprintf(os.Stderr, "WARNING: the environment variable %s is no longer used %s", constants.EnvVarAzureClientSecretValue, appRegistrationErrStr)
|
||||
}
|
||||
|
||||
openstackPassword := os.Getenv(constants.EnvVarOpenStackPassword)
|
||||
if openstackPassword != "" && c.Provider.OpenStack != nil {
|
||||
c.Provider.OpenStack.Password = openstackPassword
|
||||
}
|
||||
|
||||
return c, c.Validate(force)
|
||||
}
|
||||
|
||||
@ -720,7 +697,8 @@ func (c *Config) DeployYawolLoadBalancer() bool {
|
||||
func (c *Config) UseMarketplaceImage() bool {
|
||||
return (c.Provider.Azure != nil && c.Provider.Azure.UseMarketplaceImage != nil && *c.Provider.Azure.UseMarketplaceImage) ||
|
||||
(c.Provider.GCP != nil && c.Provider.GCP.UseMarketplaceImage != nil && *c.Provider.GCP.UseMarketplaceImage) ||
|
||||
(c.Provider.AWS != nil && c.Provider.AWS.UseMarketplaceImage != nil && *c.Provider.AWS.UseMarketplaceImage)
|
||||
(c.Provider.AWS != nil && c.Provider.AWS.UseMarketplaceImage != nil && *c.Provider.AWS.UseMarketplaceImage) ||
|
||||
(c.Provider.OpenStack != nil && c.Provider.OpenStack.Cloud == "stackit")
|
||||
}
|
||||
|
||||
// Validate checks the config values and returns validation errors.
|
||||
@ -899,14 +877,15 @@ func (c *Config) Validate(force bool) error {
|
||||
|
||||
// WithOpenStackProviderDefaults fills the default values for the specific OpenStack provider.
|
||||
// If the provider is not supported or not an OpenStack provider, the config is returned unchanged.
|
||||
func (c *Config) WithOpenStackProviderDefaults(openStackProvider string) *Config {
|
||||
func (c *Config) WithOpenStackProviderDefaults(csp cloudprovider.Provider, openStackProvider string) *Config {
|
||||
if csp != cloudprovider.OpenStack {
|
||||
return c
|
||||
}
|
||||
c.Attestation.QEMUVTPM = &QEMUVTPM{Measurements: measurements.DefaultsFor(cloudprovider.OpenStack, variant.QEMUVTPM{})}
|
||||
switch openStackProvider {
|
||||
case "stackit":
|
||||
c.Provider.OpenStack.Cloud = "stackit"
|
||||
c.Provider.OpenStack.FloatingIPPoolID = "970ace5c-458f-484a-a660-0903bcfd91ad"
|
||||
c.Provider.OpenStack.AuthURL = "https://keystone.api.iaas.eu01.stackit.cloud/v3"
|
||||
c.Provider.OpenStack.UserDomainName = "portal_mvp"
|
||||
c.Provider.OpenStack.ProjectDomainName = "portal_mvp"
|
||||
c.Provider.OpenStack.RegionName = "RegionOne"
|
||||
c.Provider.OpenStack.DeployYawolLoadBalancer = toPtr(true)
|
||||
c.Provider.OpenStack.YawolImageID = "bcd6c13e-75d1-4c3f-bf0f-8f83580cc1be"
|
||||
|
@ -276,87 +276,57 @@ func init() {
|
||||
FieldName: "openstack",
|
||||
},
|
||||
}
|
||||
OpenStackConfigDoc.Fields = make([]encoder.Doc, 16)
|
||||
OpenStackConfigDoc.Fields = make([]encoder.Doc, 10)
|
||||
OpenStackConfigDoc.Fields[0].Name = "cloud"
|
||||
OpenStackConfigDoc.Fields[0].Type = "string"
|
||||
OpenStackConfigDoc.Fields[0].Note = ""
|
||||
OpenStackConfigDoc.Fields[0].Description = "OpenStack cloud name to select from \"clouds.yaml\". Only required if config file for OpenStack is used. Fallback authentication uses environment variables. For details see: https://docs.openstack.org/openstacksdk/latest/user/config/configuration.html."
|
||||
OpenStackConfigDoc.Fields[0].Comments[encoder.LineComment] = "OpenStack cloud name to select from \"clouds.yaml\". Only required if config file for OpenStack is used. Fallback authentication uses environment variables. For details see: https://docs.openstack.org/openstacksdk/latest/user/config/configuration.html."
|
||||
OpenStackConfigDoc.Fields[1].Name = "availabilityZone"
|
||||
OpenStackConfigDoc.Fields[1].Name = "cloudsYAMLPath"
|
||||
OpenStackConfigDoc.Fields[1].Type = "string"
|
||||
OpenStackConfigDoc.Fields[1].Note = ""
|
||||
OpenStackConfigDoc.Fields[1].Description = "Availability zone to place the VMs in. For details see: https://docs.openstack.org/nova/latest/admin/availability-zones.html"
|
||||
OpenStackConfigDoc.Fields[1].Comments[encoder.LineComment] = "Availability zone to place the VMs in. For details see: https://docs.openstack.org/nova/latest/admin/availability-zones.html"
|
||||
OpenStackConfigDoc.Fields[2].Name = "floatingIPPoolID"
|
||||
OpenStackConfigDoc.Fields[1].Description = "Path to OpenStack \"clouds.yaml\" file. Only required if automatic detection fails."
|
||||
OpenStackConfigDoc.Fields[1].Comments[encoder.LineComment] = "Path to OpenStack \"clouds.yaml\" file. Only required if automatic detection fails."
|
||||
OpenStackConfigDoc.Fields[2].Name = "availabilityZone"
|
||||
OpenStackConfigDoc.Fields[2].Type = "string"
|
||||
OpenStackConfigDoc.Fields[2].Note = ""
|
||||
OpenStackConfigDoc.Fields[2].Description = "Floating IP pool to use for the VMs. For details see: https://docs.openstack.org/ocata/user-guide/cli-manage-ip-addresses.html"
|
||||
OpenStackConfigDoc.Fields[2].Comments[encoder.LineComment] = "Floating IP pool to use for the VMs. For details see: https://docs.openstack.org/ocata/user-guide/cli-manage-ip-addresses.html"
|
||||
OpenStackConfigDoc.Fields[3].Name = "authURL"
|
||||
OpenStackConfigDoc.Fields[2].Description = "Availability zone to place the VMs in. For details see: https://docs.openstack.org/nova/latest/admin/availability-zones.html"
|
||||
OpenStackConfigDoc.Fields[2].Comments[encoder.LineComment] = "Availability zone to place the VMs in. For details see: https://docs.openstack.org/nova/latest/admin/availability-zones.html"
|
||||
OpenStackConfigDoc.Fields[3].Name = "floatingIPPoolID"
|
||||
OpenStackConfigDoc.Fields[3].Type = "string"
|
||||
OpenStackConfigDoc.Fields[3].Note = ""
|
||||
OpenStackConfigDoc.Fields[3].Description = "description: |\nAuthURL is the OpenStack Identity endpoint to use inside the cluster.\n"
|
||||
OpenStackConfigDoc.Fields[3].Comments[encoder.LineComment] = "description: |"
|
||||
OpenStackConfigDoc.Fields[4].Name = "projectID"
|
||||
OpenStackConfigDoc.Fields[3].Description = "Floating IP pool to use for the VMs. For details see: https://docs.openstack.org/ocata/user-guide/cli-manage-ip-addresses.html"
|
||||
OpenStackConfigDoc.Fields[3].Comments[encoder.LineComment] = "Floating IP pool to use for the VMs. For details see: https://docs.openstack.org/ocata/user-guide/cli-manage-ip-addresses.html"
|
||||
OpenStackConfigDoc.Fields[4].Name = "stackitProjectID"
|
||||
OpenStackConfigDoc.Fields[4].Type = "string"
|
||||
OpenStackConfigDoc.Fields[4].Note = ""
|
||||
OpenStackConfigDoc.Fields[4].Description = "ProjectID is the ID of the OpenStack project where a user resides."
|
||||
OpenStackConfigDoc.Fields[4].Comments[encoder.LineComment] = "ProjectID is the ID of the OpenStack project where a user resides."
|
||||
OpenStackConfigDoc.Fields[5].Name = "stackitProjectID"
|
||||
OpenStackConfigDoc.Fields[4].Description = "STACKITProjectID is the ID of the STACKIT project where a user resides.\nOnly used if cloud is \"stackit\"."
|
||||
OpenStackConfigDoc.Fields[4].Comments[encoder.LineComment] = "STACKITProjectID is the ID of the STACKIT project where a user resides."
|
||||
OpenStackConfigDoc.Fields[5].Name = "regionName"
|
||||
OpenStackConfigDoc.Fields[5].Type = "string"
|
||||
OpenStackConfigDoc.Fields[5].Note = ""
|
||||
OpenStackConfigDoc.Fields[5].Description = "STACKITProjectID is the ID of the STACKIT project where a user resides.\nOnly used if cloud is \"stackit\"."
|
||||
OpenStackConfigDoc.Fields[5].Comments[encoder.LineComment] = "STACKITProjectID is the ID of the STACKIT project where a user resides."
|
||||
OpenStackConfigDoc.Fields[6].Name = "projectName"
|
||||
OpenStackConfigDoc.Fields[6].Type = "string"
|
||||
OpenStackConfigDoc.Fields[5].Description = "description: |\nRegionName is the name of the region to use inside the cluster.\n"
|
||||
OpenStackConfigDoc.Fields[5].Comments[encoder.LineComment] = "description: |"
|
||||
OpenStackConfigDoc.Fields[6].Name = "deployYawolLoadBalancer"
|
||||
OpenStackConfigDoc.Fields[6].Type = "bool"
|
||||
OpenStackConfigDoc.Fields[6].Note = ""
|
||||
OpenStackConfigDoc.Fields[6].Description = "ProjectName is the name of the project where a user resides."
|
||||
OpenStackConfigDoc.Fields[6].Comments[encoder.LineComment] = "ProjectName is the name of the project where a user resides."
|
||||
OpenStackConfigDoc.Fields[7].Name = "userDomainName"
|
||||
OpenStackConfigDoc.Fields[6].Description = "Deploy Yawol loadbalancer. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[6].Comments[encoder.LineComment] = "Deploy Yawol loadbalancer. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[7].Name = "yawolImageID"
|
||||
OpenStackConfigDoc.Fields[7].Type = "string"
|
||||
OpenStackConfigDoc.Fields[7].Note = ""
|
||||
OpenStackConfigDoc.Fields[7].Description = "UserDomainName is the name of the domain where a user resides."
|
||||
OpenStackConfigDoc.Fields[7].Comments[encoder.LineComment] = "UserDomainName is the name of the domain where a user resides."
|
||||
OpenStackConfigDoc.Fields[8].Name = "projectDomainName"
|
||||
OpenStackConfigDoc.Fields[7].Description = "OpenStack OS image used by the yawollet. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[7].Comments[encoder.LineComment] = "OpenStack OS image used by the yawollet. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[8].Name = "yawolFlavorID"
|
||||
OpenStackConfigDoc.Fields[8].Type = "string"
|
||||
OpenStackConfigDoc.Fields[8].Note = ""
|
||||
OpenStackConfigDoc.Fields[8].Description = "ProjectDomainName is the name of the domain where a project resides."
|
||||
OpenStackConfigDoc.Fields[8].Comments[encoder.LineComment] = "ProjectDomainName is the name of the domain where a project resides."
|
||||
OpenStackConfigDoc.Fields[9].Name = "regionName"
|
||||
OpenStackConfigDoc.Fields[9].Type = "string"
|
||||
OpenStackConfigDoc.Fields[8].Description = "OpenStack flavor id used for yawollets. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[8].Comments[encoder.LineComment] = "OpenStack flavor id used for yawollets. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[9].Name = "deployCSIDriver"
|
||||
OpenStackConfigDoc.Fields[9].Type = "bool"
|
||||
OpenStackConfigDoc.Fields[9].Note = ""
|
||||
OpenStackConfigDoc.Fields[9].Description = "description: |\nRegionName is the name of the region to use inside the cluster.\n"
|
||||
OpenStackConfigDoc.Fields[9].Comments[encoder.LineComment] = "description: |"
|
||||
OpenStackConfigDoc.Fields[10].Name = "username"
|
||||
OpenStackConfigDoc.Fields[10].Type = "string"
|
||||
OpenStackConfigDoc.Fields[10].Note = ""
|
||||
OpenStackConfigDoc.Fields[10].Description = "Username to use inside the cluster."
|
||||
OpenStackConfigDoc.Fields[10].Comments[encoder.LineComment] = "Username to use inside the cluster."
|
||||
OpenStackConfigDoc.Fields[11].Name = "password"
|
||||
OpenStackConfigDoc.Fields[11].Type = "string"
|
||||
OpenStackConfigDoc.Fields[11].Note = ""
|
||||
OpenStackConfigDoc.Fields[11].Description = "Password to use inside the cluster. You can instead use the environment variable \"CONSTELL_OS_PASSWORD\"."
|
||||
OpenStackConfigDoc.Fields[11].Comments[encoder.LineComment] = "Password to use inside the cluster. You can instead use the environment variable \"CONSTELL_OS_PASSWORD\"."
|
||||
OpenStackConfigDoc.Fields[12].Name = "deployYawolLoadBalancer"
|
||||
OpenStackConfigDoc.Fields[12].Type = "bool"
|
||||
OpenStackConfigDoc.Fields[12].Note = ""
|
||||
OpenStackConfigDoc.Fields[12].Description = "Deploy Yawol loadbalancer. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[12].Comments[encoder.LineComment] = "Deploy Yawol loadbalancer. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[13].Name = "yawolImageID"
|
||||
OpenStackConfigDoc.Fields[13].Type = "string"
|
||||
OpenStackConfigDoc.Fields[13].Note = ""
|
||||
OpenStackConfigDoc.Fields[13].Description = "OpenStack OS image used by the yawollet. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[13].Comments[encoder.LineComment] = "OpenStack OS image used by the yawollet. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[14].Name = "yawolFlavorID"
|
||||
OpenStackConfigDoc.Fields[14].Type = "string"
|
||||
OpenStackConfigDoc.Fields[14].Note = ""
|
||||
OpenStackConfigDoc.Fields[14].Description = "OpenStack flavor id used for yawollets. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[14].Comments[encoder.LineComment] = "OpenStack flavor id used for yawollets. For details see: https://github.com/stackitcloud/yawol"
|
||||
OpenStackConfigDoc.Fields[15].Name = "deployCSIDriver"
|
||||
OpenStackConfigDoc.Fields[15].Type = "bool"
|
||||
OpenStackConfigDoc.Fields[15].Note = ""
|
||||
OpenStackConfigDoc.Fields[15].Description = "Deploy Cinder CSI driver with on-node encryption. For details see: https://docs.edgeless.systems/constellation/architecture/encrypted-storage"
|
||||
OpenStackConfigDoc.Fields[15].Comments[encoder.LineComment] = "Deploy Cinder CSI driver with on-node encryption. For details see: https://docs.edgeless.systems/constellation/architecture/encrypted-storage"
|
||||
OpenStackConfigDoc.Fields[9].Description = "Deploy Cinder CSI driver with on-node encryption. For details see: https://docs.edgeless.systems/constellation/architecture/encrypted-storage"
|
||||
OpenStackConfigDoc.Fields[9].Comments[encoder.LineComment] = "Deploy Cinder CSI driver with on-node encryption. For details see: https://docs.edgeless.systems/constellation/architecture/encrypted-storage"
|
||||
|
||||
QEMUConfigDoc.Type = "QEMUConfig"
|
||||
QEMUConfigDoc.Comments[encoder.LineComment] = "QEMUConfig holds config information for QEMU based Constellation deployments."
|
||||
|
@ -328,7 +328,7 @@ func TestFromFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
const defaultErrCount = 38 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default
|
||||
const defaultErrCount = 32 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default
|
||||
const azErrCount = 7
|
||||
const awsErrCount = 8
|
||||
const gcpErrCount = 8
|
||||
|
@ -10,5 +10,5 @@ package config
|
||||
|
||||
const (
|
||||
// defaultImage is the default image to use.
|
||||
defaultImage = "ref/main/stream/nightly/v2.16.0-pre.0.20240227085922-80518379c44d"
|
||||
defaultImage = "v2.16.3"
|
||||
)
|
||||
|
@ -6,6 +6,7 @@ go_library(
|
||||
"aws.go",
|
||||
"azure.go",
|
||||
"gcp.go",
|
||||
"stackit.go",
|
||||
],
|
||||
importpath = "github.com/edgelesssys/constellation/v2/internal/config/instancetypes",
|
||||
visibility = ["//:__subpackages__"],
|
||||
|
16
internal/config/instancetypes/stackit.go
Normal file
16
internal/config/instancetypes/stackit.go
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package instancetypes
|
||||
|
||||
// STACKITInstanceTypes are valid STACKIT instance types.
|
||||
var STACKITInstanceTypes = []string{
|
||||
"m1a.2cd",
|
||||
"m1a.4cd",
|
||||
"m1a.8cd",
|
||||
"m1a.16cd",
|
||||
"m1a.30cd",
|
||||
}
|
@ -381,14 +381,7 @@ func V3ToV4(path string, fileHandler file.Handler) error {
|
||||
Cloud: cfgV3.Provider.OpenStack.Cloud,
|
||||
AvailabilityZone: cfgV3.Provider.OpenStack.AvailabilityZone,
|
||||
FloatingIPPoolID: cfgV3.Provider.OpenStack.FloatingIPPoolID,
|
||||
AuthURL: cfgV3.Provider.OpenStack.AuthURL,
|
||||
ProjectID: cfgV3.Provider.OpenStack.ProjectID,
|
||||
ProjectName: cfgV3.Provider.OpenStack.ProjectName,
|
||||
UserDomainName: cfgV3.Provider.OpenStack.UserDomainName,
|
||||
ProjectDomainName: cfgV3.Provider.OpenStack.ProjectDomainName,
|
||||
RegionName: cfgV3.Provider.OpenStack.RegionName,
|
||||
Username: cfgV3.Provider.OpenStack.Username,
|
||||
Password: cfgV3.Provider.OpenStack.Password,
|
||||
DeployYawolLoadBalancer: cfgV3.Provider.OpenStack.DeployYawolLoadBalancer,
|
||||
YawolImageID: cfgV3.Provider.OpenStack.YawolImageID,
|
||||
YawolFlavorID: cfgV3.Provider.OpenStack.YawolFlavorID,
|
||||
|
@ -9,7 +9,6 @@ package constellation
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/helm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
||||
@ -17,18 +16,18 @@ import (
|
||||
|
||||
// PrepareHelmCharts loads Helm charts for Constellation and returns an executor to apply them.
|
||||
func (a *Applier) PrepareHelmCharts(
|
||||
flags helm.Options, state *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags helm.Options, state *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (helm.Applier, bool, error) {
|
||||
if a.helmClient == nil {
|
||||
return nil, false, errors.New("helm client not initialized")
|
||||
}
|
||||
|
||||
return a.helmClient.PrepareApply(flags, state, serviceAccURI, masterSecret, openStackCfg)
|
||||
return a.helmClient.PrepareApply(flags, state, serviceAccURI, masterSecret)
|
||||
}
|
||||
|
||||
type helmApplier interface {
|
||||
PrepareApply(
|
||||
flags helm.Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags helm.Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (
|
||||
helm.Applier, bool, error)
|
||||
}
|
||||
|
@ -467,7 +467,6 @@ go_library(
|
||||
"//internal/cloud/gcpshared",
|
||||
"//internal/cloud/openstack",
|
||||
"//internal/compatibility",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
"//internal/constellation/helm/imageversion",
|
||||
"//internal/constellation/state",
|
||||
|
@ -8,8 +8,10 @@ package helm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
@ -52,6 +54,12 @@ func newHelmInstallAction(config *action.Configuration, release release, timeout
|
||||
return action
|
||||
}
|
||||
|
||||
func newHelmUninstallAction(config *action.Configuration, timeout time.Duration) *action.Uninstall {
|
||||
action := action.NewUninstall(config)
|
||||
action.Timeout = timeout
|
||||
return action
|
||||
}
|
||||
|
||||
func setWaitMode(a *action.Install, waitMode WaitMode) {
|
||||
switch waitMode {
|
||||
case WaitModeNone:
|
||||
@ -70,11 +78,12 @@ func setWaitMode(a *action.Install, waitMode WaitMode) {
|
||||
|
||||
// installAction is an action that installs a helm chart.
|
||||
type installAction struct {
|
||||
preInstall func(context.Context) error
|
||||
release release
|
||||
helmAction *action.Install
|
||||
postInstall func(context.Context) error
|
||||
log debugLog
|
||||
preInstall func(context.Context) error
|
||||
release release
|
||||
helmAction *action.Install
|
||||
uninstallAction *action.Uninstall
|
||||
postInstall func(context.Context) error
|
||||
log debugLog
|
||||
}
|
||||
|
||||
// Apply installs the chart.
|
||||
@ -103,6 +112,11 @@ func (a *installAction) SaveChart(chartsDir string, fileHandler file.Handler) er
|
||||
|
||||
func (a *installAction) apply(ctx context.Context) error {
|
||||
_, err := a.helmAction.RunWithContext(ctx, a.release.chart, a.release.values)
|
||||
if isUninstallError(err) && a.uninstallAction != nil {
|
||||
a.log.Debug("cleaning up manually after failed atomic Helm install", "error", err, "release", a.release.releaseName)
|
||||
_, uninstallErr := a.uninstallAction.Run(a.release.releaseName)
|
||||
err = errors.Join(err, uninstallErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@ -228,3 +242,8 @@ func helmLog(log debugLog) action.DebugLog {
|
||||
log.Debug(fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func isUninstallError(err error) bool {
|
||||
return err != nil && (strings.Contains(err.Error(), "an error occurred while uninstalling the release") ||
|
||||
strings.Contains(err.Error(), "cannot re-use a name that is still in use"))
|
||||
}
|
||||
|
@ -139,6 +139,9 @@ func (a actionFactory) appendNewAction(
|
||||
|
||||
func (a actionFactory) newInstall(release release, timeout time.Duration) *installAction {
|
||||
action := &installAction{helmAction: newHelmInstallAction(a.cfg, release, timeout), release: release, log: a.log}
|
||||
if action.IsAtomic() {
|
||||
action.uninstallAction = newHelmUninstallAction(a.cfg, timeout)
|
||||
}
|
||||
return action
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@ apiVersion: v2
|
||||
name: cilium
|
||||
displayName: Cilium
|
||||
home: https://cilium.io/
|
||||
version: 1.15.0-pre.3-edg.2
|
||||
appVersion: 1.15.0-pre.3-edg.2
|
||||
version: 1.15.0-pre.3-edg.3
|
||||
appVersion: 1.15.0-pre.3-edg.3
|
||||
kubeVersion: ">= 1.16.0-0"
|
||||
icon: https://cdn.jsdelivr.net/gh/cilium/cilium@main/Documentation/images/logo-solo.svg
|
||||
description: eBPF-based Networking, Security, and Observability
|
||||
|
@ -715,6 +715,37 @@ spec:
|
||||
- name: cni-path
|
||||
mountPath: /host/opt/cni/bin
|
||||
{{- end }} # .Values.cni.install
|
||||
- name: firewall-pods
|
||||
image: ghcr.io/edgelesssys/cilium/cilium:v1.15.0-pre.3-edg.2@sha256:c21b7fbbb084a128a479d6170e5f89ad2768dfecb4af10ee6a99ffe5d1a11749
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- /bin/bash
|
||||
- -exc
|
||||
- |
|
||||
pref=32
|
||||
interface=$(ip route | awk '/^default/ { print $5 }')
|
||||
tc qdisc add dev "${interface}" clsact || true
|
||||
tc filter del dev "${interface}" ingress pref "${pref}" 2>/dev/null || true
|
||||
handle=0
|
||||
for cidr in ${POD_CIDRS}; do
|
||||
handle=$((handle + 1))
|
||||
tc filter replace dev "${interface}" ingress pref "${pref}" handle "${handle}" protocol ip flower dst_ip "${cidr}" action drop
|
||||
done
|
||||
env:
|
||||
- name: POD_CIDRS
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: encryption-strict-mode-pod-cidrs
|
||||
name: cilium-config
|
||||
optional: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- NET_ADMIN
|
||||
restartPolicy: Always
|
||||
priorityClassName: {{ include "cilium.priorityClass" (list $ .Values.priorityClassName "system-node-critical") }}
|
||||
serviceAccount: {{ .Values.serviceAccounts.cilium.name | quote }}
|
||||
|
@ -54,8 +54,50 @@ index 256a79542..3f3fc714b 100644
|
||||
home: https://cilium.io/
|
||||
-version: 1.15.0-pre.3
|
||||
-appVersion: 1.15.0-pre.3
|
||||
+version: 1.15.0-pre.3-edg.2
|
||||
+appVersion: 1.15.0-pre.3-edg.2
|
||||
+version: 1.15.0-pre.3-edg.3
|
||||
+appVersion: 1.15.0-pre.3-edg.3
|
||||
kubeVersion: ">= 1.16.0-0"
|
||||
icon: https://cdn.jsdelivr.net/gh/cilium/cilium@main/Documentation/images/logo-solo.svg
|
||||
description: eBPF-based Networking, Security, and Observability
|
||||
diff --git a/install/kubernetes/cilium/templates/cilium-agent/daemonset.yaml b/install/kubernetes/cilium/templates/cilium-agent/daemonset.yaml
|
||||
index f6b493cb7..50b80267a 100644
|
||||
--- a/install/kubernetes/cilium/templates/cilium-agent/daemonset.yaml
|
||||
+++ b/install/kubernetes/cilium/templates/cilium-agent/daemonset.yaml
|
||||
@@ -715,6 +715,37 @@ spec:
|
||||
- name: cni-path
|
||||
mountPath: /host/opt/cni/bin
|
||||
{{- end }} # .Values.cni.install
|
||||
+ - name: firewall-pods
|
||||
+ image: ghcr.io/edgelesssys/cilium/cilium:v1.15.0-pre.3-edg.2@sha256:c21b7fbbb084a128a479d6170e5f89ad2768dfecb4af10ee6a99ffe5d1a11749
|
||||
+ imagePullPolicy: IfNotPresent
|
||||
+ command:
|
||||
+ - /bin/bash
|
||||
+ - -exc
|
||||
+ - |
|
||||
+ pref=32
|
||||
+ interface=$(ip route | awk '/^default/ { print $5 }')
|
||||
+ tc qdisc add dev "${interface}" clsact || true
|
||||
+ tc filter del dev "${interface}" ingress pref "${pref}" 2>/dev/null || true
|
||||
+ handle=0
|
||||
+ for cidr in ${POD_CIDRS}; do
|
||||
+ handle=$((handle + 1))
|
||||
+ tc filter replace dev "${interface}" ingress pref "${pref}" handle "${handle}" protocol ip flower dst_ip "${cidr}" action drop
|
||||
+ done
|
||||
+ env:
|
||||
+ - name: POD_CIDRS
|
||||
+ valueFrom:
|
||||
+ configMapKeyRef:
|
||||
+ key: encryption-strict-mode-pod-cidrs
|
||||
+ name: cilium-config
|
||||
+ optional: true
|
||||
+ resources:
|
||||
+ requests:
|
||||
+ cpu: 100m
|
||||
+ memory: 20Mi
|
||||
+ securityContext:
|
||||
+ capabilities:
|
||||
+ add:
|
||||
+ - NET_ADMIN
|
||||
restartPolicy: Always
|
||||
priorityClassName: {{ include "cilium.priorityClass" (list $ .Values.priorityClassName "system-node-critical") }}
|
||||
serviceAccount: {{ .Values.serviceAccounts.cilium.name | quote }}
|
||||
|
@ -35,7 +35,6 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
@ -91,13 +90,14 @@ type Options struct {
|
||||
MicroserviceVersion semver.Semver
|
||||
HelmWaitMode WaitMode
|
||||
ApplyTimeout time.Duration
|
||||
OpenStackValues *OpenStackValues
|
||||
}
|
||||
|
||||
// PrepareApply loads the charts and returns the executor to apply them.
|
||||
func (h Client) PrepareApply(
|
||||
flags Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret, openStackCfg *config.OpenStackConfig,
|
||||
flags Options, stateFile *state.State, serviceAccURI string, masterSecret uri.MasterSecret,
|
||||
) (Applier, bool, error) {
|
||||
releases, err := h.loadReleases(flags.CSP, flags.AttestationVariant, flags.K8sVersion, masterSecret, stateFile, flags, serviceAccURI, openStackCfg)
|
||||
releases, err := h.loadReleases(masterSecret, stateFile, flags, serviceAccURI)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("loading Helm releases: %w", err)
|
||||
}
|
||||
@ -110,12 +110,11 @@ func (h Client) PrepareApply(
|
||||
}
|
||||
|
||||
func (h Client) loadReleases(
|
||||
csp cloudprovider.Provider, attestationVariant variant.Variant, k8sVersion versions.ValidK8sVersion, secret uri.MasterSecret,
|
||||
stateFile *state.State, flags Options, serviceAccURI string, openStackCfg *config.OpenStackConfig,
|
||||
secret uri.MasterSecret, stateFile *state.State, flags Options, serviceAccURI string,
|
||||
) ([]release, error) {
|
||||
helmLoader := newLoader(csp, attestationVariant, k8sVersion, stateFile, h.cliVersion)
|
||||
helmLoader := newLoader(flags.CSP, flags.AttestationVariant, flags.K8sVersion, stateFile, h.cliVersion)
|
||||
h.log.Debug("Created new Helm loader")
|
||||
return helmLoader.loadReleases(flags.Conformance, flags.DeployCSIDriver, flags.HelmWaitMode, secret, serviceAccURI, openStackCfg)
|
||||
return helmLoader.loadReleases(flags.Conformance, flags.DeployCSIDriver, flags.HelmWaitMode, secret, serviceAccURI, flags.OpenStackValues)
|
||||
}
|
||||
|
||||
// Applier runs the Helm actions.
|
||||
|
@ -198,7 +198,7 @@ func TestHelmApply(t *testing.T) {
|
||||
if tc.clusterCertManagerVersion != nil {
|
||||
certManagerVersion = *tc.clusterCertManagerVersion
|
||||
}
|
||||
helmListVersion(lister, "cilium", "v1.15.0-pre.3-edg.2")
|
||||
helmListVersion(lister, "cilium", "v1.15.0-pre.3-edg.3")
|
||||
helmListVersion(lister, "cert-manager", certManagerVersion)
|
||||
helmListVersion(lister, "constellation-services", tc.clusterMicroServiceVersion)
|
||||
helmListVersion(lister, "constellation-operators", tc.clusterMicroServiceVersion)
|
||||
@ -217,7 +217,7 @@ func TestHelmApply(t *testing.T) {
|
||||
SetInfrastructure(state.Infrastructure{UID: "testuid"}).
|
||||
SetClusterValues(state.ClusterValues{MeasurementSalt: []byte{0x41}}),
|
||||
fakeServiceAccURI(csp),
|
||||
uri.MasterSecret{Key: []byte("secret"), Salt: []byte("masterSalt")}, nil)
|
||||
uri.MasterSecret{Key: []byte("secret"), Salt: []byte("masterSalt")})
|
||||
var upgradeErr *compatibility.InvalidUpgradeError
|
||||
if tc.expectError {
|
||||
assert.Error(t, err)
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/helm/imageversion"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
@ -115,9 +114,17 @@ func newLoader(csp cloudprovider.Provider, attestationVariant variant.Variant, k
|
||||
// that the new release is installed after the existing one to avoid name conflicts.
|
||||
type releaseApplyOrder []release
|
||||
|
||||
// OpenStackValues are helm values for OpenStack.
|
||||
type OpenStackValues struct {
|
||||
DeployYawolLoadBalancer bool
|
||||
FloatingIPPoolID string
|
||||
YawolFlavorID string
|
||||
YawolImageID string
|
||||
}
|
||||
|
||||
// loadReleases loads the embedded helm charts and returns them as a HelmReleases object.
|
||||
func (i *chartLoader) loadReleases(conformanceMode, deployCSIDriver bool, helmWaitMode WaitMode, masterSecret uri.MasterSecret,
|
||||
serviceAccURI string, openStackCfg *config.OpenStackConfig,
|
||||
serviceAccURI string, openStackValues *OpenStackValues,
|
||||
) (releaseApplyOrder, error) {
|
||||
ciliumRelease, err := i.loadRelease(ciliumInfo, helmWaitMode)
|
||||
if err != nil {
|
||||
@ -143,7 +150,7 @@ func (i *chartLoader) loadReleases(conformanceMode, deployCSIDriver bool, helmWa
|
||||
}
|
||||
|
||||
svcVals, err := extraConstellationServicesValues(i.csp, i.attestationVariant, masterSecret,
|
||||
serviceAccURI, i.stateFile.Infrastructure, openStackCfg)
|
||||
serviceAccURI, i.stateFile.Infrastructure, openStackValues)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("extending constellation-services values: %w", err)
|
||||
}
|
||||
@ -169,18 +176,23 @@ func (i *chartLoader) loadReleases(conformanceMode, deployCSIDriver bool, helmWa
|
||||
}
|
||||
releases = append(releases, awsRelease)
|
||||
}
|
||||
if i.csp == cloudprovider.OpenStack && openStackCfg.DeployYawolLoadBalancer != nil && *openStackCfg.DeployYawolLoadBalancer {
|
||||
yawolRelease, err := i.loadRelease(yawolLBControllerInfo, WaitModeNone)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading yawol chart: %w", err)
|
||||
if i.csp == cloudprovider.OpenStack {
|
||||
if openStackValues == nil {
|
||||
return nil, errors.New("provider is OpenStack but OpenStack config is missing")
|
||||
}
|
||||
if openStackValues.DeployYawolLoadBalancer {
|
||||
yawolRelease, err := i.loadRelease(yawolLBControllerInfo, WaitModeNone)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading yawol chart: %w", err)
|
||||
}
|
||||
|
||||
yawolVals, err := extraYawolValues(serviceAccURI, i.stateFile.Infrastructure, openStackCfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("extending yawol chart values: %w", err)
|
||||
yawolVals, err := extraYawolValues(serviceAccURI, i.stateFile.Infrastructure, openStackValues)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("extending yawol chart values: %w", err)
|
||||
}
|
||||
yawolRelease.values = mergeMaps(yawolRelease.values, yawolVals)
|
||||
releases = append(releases, yawolRelease)
|
||||
}
|
||||
yawolRelease.values = mergeMaps(yawolRelease.values, yawolVals)
|
||||
releases = append(releases, yawolRelease)
|
||||
}
|
||||
|
||||
return releases, nil
|
||||
@ -347,7 +359,7 @@ func (i *chartLoader) cspTags() map[string]any {
|
||||
|
||||
func (i *chartLoader) loadCiliumValues(cloudprovider.Provider) (map[string]any, error) {
|
||||
sharedConfig := map[string]any{
|
||||
"extraArgs": []string{"--node-encryption-opt-out-labels=invalid.label"},
|
||||
"extraArgs": []string{"--node-encryption-opt-out-labels=invalid.label", "--bpf-filter-priority=128"},
|
||||
"endpointRoutes": map[string]any{
|
||||
"enabled": true,
|
||||
},
|
||||
@ -400,6 +412,7 @@ func (i *chartLoader) loadCiliumValues(cloudprovider.Provider) (map[string]any,
|
||||
"kubeProxyReplacement": "strict",
|
||||
"enableCiliumEndpointSlice": true,
|
||||
"kubeProxyReplacementHealthzBindAddr": "0.0.0.0:10256",
|
||||
"cleanBpfState": true,
|
||||
}
|
||||
cspOverrideConfigs := map[string]map[string]any{
|
||||
cloudprovider.AWS.String(): {},
|
||||
|
@ -175,6 +175,19 @@ func TestConstellationServices(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
var openstackValues *OpenStackValues
|
||||
if tc.config.Provider.OpenStack != nil {
|
||||
var deploy bool
|
||||
if tc.config.Provider.OpenStack.DeployYawolLoadBalancer != nil {
|
||||
deploy = *tc.config.Provider.OpenStack.DeployYawolLoadBalancer
|
||||
}
|
||||
openstackValues = &OpenStackValues{
|
||||
DeployYawolLoadBalancer: deploy,
|
||||
FloatingIPPoolID: tc.config.Provider.OpenStack.FloatingIPPoolID,
|
||||
YawolFlavorID: tc.config.Provider.OpenStack.YawolFlavorID,
|
||||
YawolImageID: tc.config.Provider.OpenStack.YawolImageID,
|
||||
}
|
||||
}
|
||||
|
||||
chartLoader := chartLoader{
|
||||
csp: tc.config.GetProvider(),
|
||||
@ -199,7 +212,7 @@ func TestConstellationServices(t *testing.T) {
|
||||
UID: "uid",
|
||||
Azure: &state.Azure{},
|
||||
GCP: &state.GCP{},
|
||||
}, tc.config.Provider.OpenStack)
|
||||
}, openstackValues)
|
||||
require.NoError(err)
|
||||
values = mergeMaps(values, extraVals)
|
||||
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/gcpshared"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/openstack"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
||||
@ -83,7 +82,7 @@ func extraCiliumValues(provider cloudprovider.Provider, conformanceMode bool, ou
|
||||
// Values set inside this function are only applied during init, not during upgrade.
|
||||
func extraConstellationServicesValues(
|
||||
csp cloudprovider.Provider, attestationVariant variant.Variant, masterSecret uri.MasterSecret, serviceAccURI string,
|
||||
output state.Infrastructure, openStackCfg *config.OpenStackConfig,
|
||||
output state.Infrastructure, openStackCfg *OpenStackValues,
|
||||
) (map[string]any, error) {
|
||||
extraVals := map[string]any{}
|
||||
extraVals["join-service"] = map[string]any{
|
||||
@ -152,7 +151,7 @@ func extraConstellationServicesValues(
|
||||
|
||||
// extraYawolValues extends the given values map by some values depending on user input.
|
||||
// Values set inside this function are only applied during init, not during upgrade.
|
||||
func extraYawolValues(serviceAccURI string, output state.Infrastructure, openStackCfg *config.OpenStackConfig) (map[string]any, error) {
|
||||
func extraYawolValues(serviceAccURI string, output state.Infrastructure, openStackCfg *OpenStackValues) (map[string]any, error) {
|
||||
extraVals := map[string]any{}
|
||||
|
||||
creds, err := openstack.AccountKeyFromURI(serviceAccURI)
|
||||
@ -163,7 +162,7 @@ func extraYawolValues(serviceAccURI string, output state.Infrastructure, openSta
|
||||
extraVals["yawol-config"] = map[string]any{
|
||||
"secretData": yawolIni,
|
||||
}
|
||||
if openStackCfg.DeployYawolLoadBalancer != nil && *openStackCfg.DeployYawolLoadBalancer {
|
||||
if openStackCfg != nil && openStackCfg.DeployYawolLoadBalancer {
|
||||
extraVals["yawol-controller"] = map[string]any{
|
||||
"yawolOSSecretName": "yawolkey",
|
||||
// has to be larger than ~30s to account for slow OpenStack API calls.
|
||||
|
@ -16,9 +16,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
authEOFErr = `connection error: desc = "transport: authentication handshake failed: EOF"`
|
||||
authReadTCPErr = `connection error: desc = "transport: authentication handshake failed: read tcp`
|
||||
authHandshakeErr = `connection error: desc = "transport: authentication handshake failed`
|
||||
authEOFErr = `connection error: desc = "transport: authentication handshake failed: EOF"`
|
||||
authReadTCPErr = `connection error: desc = "transport: authentication handshake failed: read tcp`
|
||||
authHandshakeErr = `connection error: desc = "transport: authentication handshake failed`
|
||||
authHandshakeDeadlineExceededErr = `connection error: desc = "transport: authentication handshake failed: context deadline exceeded`
|
||||
)
|
||||
|
||||
// grpcErr is the error type that is returned by the grpc client.
|
||||
@ -57,6 +58,11 @@ func ServiceIsUnavailable(err error) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// retry if the handshake deadline was exceeded
|
||||
if strings.HasPrefix(statusErr.Message(), authHandshakeDeadlineExceededErr) {
|
||||
return true
|
||||
}
|
||||
|
||||
return !strings.HasPrefix(statusErr.Message(), authHandshakeErr)
|
||||
}
|
||||
|
||||
@ -76,6 +82,11 @@ func LoadbalancerIsNotReady(err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// retry if the handshake deadline was exceeded
|
||||
if strings.HasPrefix(statusErr.Message(), authHandshakeDeadlineExceededErr) {
|
||||
return true
|
||||
}
|
||||
|
||||
// retry if GCP proxy LB isn't fully available yet
|
||||
return strings.HasPrefix(statusErr.Message(), authReadTCPErr)
|
||||
}
|
||||
|
@ -43,6 +43,10 @@ func TestServiceIsUnavailable(t *testing.T) {
|
||||
err: status.Error(codes.Unavailable, `connection error: desc = "transport: authentication handshake failed: read tcp error"`),
|
||||
wantUnavailable: true,
|
||||
},
|
||||
"handshake deadline exceeded error": {
|
||||
err: status.Error(codes.Unavailable, `connection error: desc = "transport: authentication handshake failed: context deadline exceeded"`),
|
||||
wantUnavailable: true,
|
||||
},
|
||||
"wrapped error": {
|
||||
err: fmt.Errorf("some wrapping: %w", status.Error(codes.Unavailable, "error")),
|
||||
wantUnavailable: true,
|
||||
@ -82,6 +86,10 @@ func TestLoadbalancerIsNotReady(t *testing.T) {
|
||||
err: status.Error(codes.Unavailable, `connection error: desc = "transport: authentication handshake failed: read tcp error"`),
|
||||
wantNotReady: true,
|
||||
},
|
||||
"handshake deadline exceeded error": {
|
||||
err: status.Error(codes.Unavailable, `connection error: desc = "transport: authentication handshake failed: context deadline exceeded"`),
|
||||
wantNotReady: true,
|
||||
},
|
||||
"normal unavailable error": {
|
||||
err: status.Error(codes.Unavailable, "error"),
|
||||
},
|
||||
|
@ -111,7 +111,7 @@ func buildMarketplaceImage(payload marketplaceImagePayload) (string, error) {
|
||||
return "", fmt.Errorf("parsing image version: %w", err)
|
||||
}
|
||||
|
||||
if sv.Prerelease() != "" {
|
||||
if sv.Prerelease() != "" && payload.provider != cloudprovider.OpenStack {
|
||||
return "", fmt.Errorf("marketplace images are not supported for prerelease versions")
|
||||
}
|
||||
|
||||
@ -131,6 +131,9 @@ func buildMarketplaceImage(payload marketplaceImagePayload) (string, error) {
|
||||
case cloudprovider.AWS:
|
||||
// For AWS, we use the AMI alias, which just needs the version and infers the rest transparently.
|
||||
return fmt.Sprintf("resolve:ssm:/aws/service/marketplace/prod-77ylkenlkgufs/%s", payload.imgInfo.Version), nil
|
||||
case cloudprovider.OpenStack:
|
||||
// For OpenStack / STACKIT, we use the image reference directly.
|
||||
return getReferenceFromImageInfo(payload.provider, payload.attestationVariant.String(), payload.imgInfo, payload.filters...)
|
||||
default:
|
||||
return "", fmt.Errorf("marketplace images are not supported for csp %s", payload.provider.String())
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ type Action string
|
||||
const (
|
||||
// CommunityLicense is used by everyone who has not bought an enterprise license.
|
||||
CommunityLicense = "00000000-0000-0000-0000-000000000000"
|
||||
// MarketplaceLicense is used by everyone who uses a marketplace image.
|
||||
MarketplaceLicense = "11111111-1111-1111-1111-111111111111"
|
||||
|
||||
// Init action denotes the initialization of a Constellation cluster.
|
||||
Init Action = "init"
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.22.1
|
||||
// source: internal/versions/components/components.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.22.1
|
||||
// source: joinservice/joinproto/join.proto
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc v4.22.1
|
||||
// source: keyservice/keyserviceproto/keyservice.proto
|
||||
|
||||
|
@ -2,4 +2,4 @@ apiVersion: v2
|
||||
name: s3proxy
|
||||
description: Helm chart to deploy s3proxy.
|
||||
type: application
|
||||
version: 0.0.0
|
||||
version: 2.16.3
|
||||
|
@ -6,6 +6,7 @@ go_binary(
|
||||
name = "tf_provider",
|
||||
out = "terraform-provider-constellation", # for complying with Terraform provider naming convention
|
||||
embed = [":terraform-provider-constellation_lib"],
|
||||
gotags = ["enterprise"],
|
||||
pure = "on",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
@ -33,6 +33,7 @@ data "constellation_attestation" "test" {
|
||||
* `azure-sev-snp`
|
||||
* `azure-tdx`
|
||||
* `gcp-sev-es`
|
||||
* `qemu-vtpm`
|
||||
- `csp` (String) CSP (Cloud Service Provider) to use. (e.g. `azure`)
|
||||
See the [full list of CSPs](https://docs.edgeless.systems/constellation/overview/clouds) that Constellation supports.
|
||||
- `image` (Attributes) Constellation OS Image to use on the nodes. (see [below for nested schema](#nestedatt--image))
|
||||
@ -58,6 +59,10 @@ Required:
|
||||
- `$SEMANTIC_VERSION` is the semantic version of the image, e.g. `vX.Y.Z` or `vX.Y.Z-pre...`.
|
||||
- `version` (String) Semantic version of the image.
|
||||
|
||||
Optional:
|
||||
|
||||
- `marketplace_image` (Boolean) Whether a marketplace image should be used.
|
||||
|
||||
|
||||
<a id="nestedatt--attestation"></a>
|
||||
### Nested Schema for `attestation`
|
||||
@ -78,6 +83,7 @@ Read-Only:
|
||||
* `azure-sev-snp`
|
||||
* `azure-tdx`
|
||||
* `gcp-sev-es`
|
||||
* `qemu-vtpm`
|
||||
|
||||
<a id="nestedatt--attestation--azure_firmware_signer_config"></a>
|
||||
### Nested Schema for `attestation.azure_firmware_signer_config`
|
||||
|
@ -32,6 +32,7 @@ data "constellation_image" "example" {
|
||||
* `azure-sev-snp`
|
||||
* `azure-tdx`
|
||||
* `gcp-sev-es`
|
||||
* `qemu-vtpm`
|
||||
- `csp` (String) CSP (Cloud Service Provider) to use. (e.g. `azure`)
|
||||
See the [full list of CSPs](https://docs.edgeless.systems/constellation/overview/clouds) that Constellation supports.
|
||||
|
||||
@ -49,6 +50,10 @@ The Constellation OS image must be [replicated to the region](https://docs.edgel
|
||||
<a id="nestedatt--image"></a>
|
||||
### Nested Schema for `image`
|
||||
|
||||
Optional:
|
||||
|
||||
- `marketplace_image` (Boolean) Whether a marketplace image should be used.
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `reference` (String) CSP-specific unique reference to the image. The format differs per CSP.
|
||||
|
@ -86,6 +86,7 @@ See the [full list of CSPs](https://docs.edgeless.systems/constellation/overview
|
||||
- `gcp` (Attributes) GCP-specific configuration. (see [below for nested schema](#nestedatt--gcp))
|
||||
- `in_cluster_endpoint` (String) The endpoint of the cluster. When not set, the out-of-cluster endpoint is used.
|
||||
- `license_id` (String) Constellation license ID. When not set, the community license is used.
|
||||
- `openstack` (Attributes) OpenStack-specific configuration. (see [below for nested schema](#nestedatt--openstack))
|
||||
|
||||
### Read-Only
|
||||
|
||||
@ -110,6 +111,7 @@ Required:
|
||||
* `azure-sev-snp`
|
||||
* `azure-tdx`
|
||||
* `gcp-sev-es`
|
||||
* `qemu-vtpm`
|
||||
|
||||
Optional:
|
||||
|
||||
@ -162,6 +164,10 @@ Required:
|
||||
- `$SEMANTIC_VERSION` is the semantic version of the image, e.g. `vX.Y.Z` or `vX.Y.Z-pre...`.
|
||||
- `version` (String) Semantic version of the image.
|
||||
|
||||
Optional:
|
||||
|
||||
- `marketplace_image` (Boolean) Whether a marketplace image should be used.
|
||||
|
||||
|
||||
<a id="nestedatt--network_config"></a>
|
||||
### Nested Schema for `network_config`
|
||||
@ -207,6 +213,24 @@ Required:
|
||||
- `project_id` (String) ID of the GCP project the cluster resides in.
|
||||
- `service_account_key` (String) Base64-encoded private key JSON object of the service account used within the cluster.
|
||||
|
||||
|
||||
<a id="nestedatt--openstack"></a>
|
||||
### Nested Schema for `openstack`
|
||||
|
||||
Required:
|
||||
|
||||
- `cloud` (String) Name of the cloud in the clouds.yaml file.
|
||||
- `floating_ip_pool_id` (String) Floating IP pool to use for the VMs.
|
||||
- `network_id` (String) OpenStack network ID to use for the VMs.
|
||||
- `subnet_id` (String) OpenStack subnet ID to use for the VMs.
|
||||
|
||||
Optional:
|
||||
|
||||
- `clouds_yaml_path` (String) Path to the clouds.yaml file.
|
||||
- `deploy_yawol_load_balancer` (Boolean) Whether to deploy a YAWOL load balancer.
|
||||
- `yawol_flavor_id` (String) OpenStack flavor used by the yawollet.
|
||||
- `yawol_image_id` (String) OpenStack OS image used by the yawollet.
|
||||
|
||||
## Import
|
||||
|
||||
Import is supported using the following syntax:
|
||||
|
@ -44,8 +44,8 @@ module "azure_iam" {
|
||||
// replace $VERSION with the Constellation version you want to use, e.g., v2.14.0
|
||||
source = "https://github.com/edgelesssys/constellation/releases/download/$VERSION/terraform-module.zip//terraform-module/iam/azure"
|
||||
location = local.location
|
||||
service_principal_name = "${local.name}-test-sp"
|
||||
resource_group_name = "${local.name}-test-rg"
|
||||
service_principal_name = "${local.name}-sp"
|
||||
resource_group_name = "${local.name}-rg"
|
||||
}
|
||||
|
||||
module "azure_infrastructure" {
|
||||
|
@ -46,7 +46,7 @@ module "gcp_iam" {
|
||||
// replace $VERSION with the Constellation version you want to use, e.g., v2.14.0
|
||||
source = "https://github.com/edgelesssys/constellation/releases/download/$VERSION/terraform-module.zip//terraform-module/iam/gcp"
|
||||
project_id = local.project_id
|
||||
service_account_id = "${local.name}-test-sa"
|
||||
service_account_id = "${local.name}-sa"
|
||||
zone = local.zone
|
||||
region = local.region
|
||||
}
|
||||
|
128
terraform-provider-constellation/examples/full/stackit/main.tf
Normal file
128
terraform-provider-constellation/examples/full/stackit/main.tf
Normal file
@ -0,0 +1,128 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
constellation = {
|
||||
source = "edgelesssys/constellation"
|
||||
version = "0.0.0" // replace with the version you want to use
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "3.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
name = "constell"
|
||||
image_version = "vX.Y.Z"
|
||||
kubernetes_version = "vX.Y.Z"
|
||||
microservice_version = "vX.Y.Z"
|
||||
csp = "stackit"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
zone = "eu01-1"
|
||||
cloud = "stackit"
|
||||
clouds_yaml_path = "~/.config/openstack/clouds.yaml"
|
||||
floating_ip_pool_id = "970ace5c-458f-484a-a660-0903bcfd91ad"
|
||||
stackit_project_id = "" // replace with the STACKIT project id
|
||||
control_plane_count = 3
|
||||
worker_count = 2
|
||||
instance_type = "m1a.8cd"
|
||||
deploy_yawol_load_balancer = true
|
||||
yawol_image_id = "bcd6c13e-75d1-4c3f-bf0f-8f83580cc1be"
|
||||
yawol_flavor_id = "3b11b27e-6c73-470d-b595-1d85b95a8cdf"
|
||||
|
||||
master_secret = random_bytes.master_secret.hex
|
||||
master_secret_salt = random_bytes.master_secret_salt.hex
|
||||
measurement_salt = random_bytes.measurement_salt.hex
|
||||
}
|
||||
|
||||
resource "random_bytes" "master_secret" {
|
||||
length = 32
|
||||
}
|
||||
|
||||
resource "random_bytes" "master_secret_salt" {
|
||||
length = 32
|
||||
}
|
||||
|
||||
resource "random_bytes" "measurement_salt" {
|
||||
length = 32
|
||||
}
|
||||
|
||||
module "stackit_infrastructure" {
|
||||
// replace $VERSION with the Constellation version you want to use, e.g., v2.14.0
|
||||
source = "https://github.com/edgelesssys/constellation/releases/download/$VERSION/terraform-module.zip//terraform-module/openstack"
|
||||
name = local.name
|
||||
node_groups = {
|
||||
control_plane_default = {
|
||||
role = "control-plane"
|
||||
flavor_id = local.instance_type
|
||||
state_disk_size = 30
|
||||
state_disk_type = "storage_premium_perf6"
|
||||
initial_count = local.control_plane_count
|
||||
zone = local.zone
|
||||
},
|
||||
worker_default = {
|
||||
role = "worker"
|
||||
flavor_id = local.instance_type
|
||||
state_disk_size = 30
|
||||
state_disk_type = "storage_premium_perf6"
|
||||
initial_count = local.worker_count
|
||||
zone = local.zone
|
||||
}
|
||||
}
|
||||
image_id = data.constellation_image.bar.image.reference
|
||||
debug = false
|
||||
cloud = local.cloud
|
||||
openstack_clouds_yaml_path = local.clouds_yaml_path
|
||||
floating_ip_pool_id = local.floating_ip_pool_id
|
||||
stackit_project_id = local.stackit_project_id
|
||||
}
|
||||
|
||||
data "constellation_attestation" "foo" {
|
||||
csp = local.csp
|
||||
attestation_variant = local.attestation_variant
|
||||
image = data.constellation_image.bar.image
|
||||
}
|
||||
|
||||
data "constellation_image" "bar" {
|
||||
csp = local.csp
|
||||
attestation_variant = local.attestation_variant
|
||||
version = local.image_version
|
||||
marketplace_image = true
|
||||
}
|
||||
|
||||
resource "constellation_cluster" "stackit_example" {
|
||||
csp = local.csp
|
||||
name = module.stackit_infrastructure.name
|
||||
uid = module.stackit_infrastructure.uid
|
||||
image = data.constellation_image.bar.image
|
||||
attestation = data.constellation_attestation.foo.attestation
|
||||
kubernetes_version = local.kubernetes_version
|
||||
constellation_microservice_version = local.microservice_version
|
||||
init_secret = module.stackit_infrastructure.init_secret
|
||||
master_secret = local.master_secret
|
||||
master_secret_salt = local.master_secret_salt
|
||||
measurement_salt = local.measurement_salt
|
||||
out_of_cluster_endpoint = module.stackit_infrastructure.out_of_cluster_endpoint
|
||||
in_cluster_endpoint = module.stackit_infrastructure.in_cluster_endpoint
|
||||
api_server_cert_sans = module.stackit_infrastructure.api_server_cert_sans
|
||||
openstack = {
|
||||
cloud = local.cloud
|
||||
clouds_yaml_path = local.clouds_yaml_path
|
||||
floating_ip_pool_id = local.floating_ip_pool_id
|
||||
deploy_yawol_load_balancer = local.deploy_yawol_load_balancer
|
||||
yawol_image_id = local.yawol_image_id
|
||||
yawol_flavor_id = local.yawol_flavor_id
|
||||
network_id = module.stackit_infrastructure.network_id
|
||||
subnet_id = module.stackit_infrastructure.lb_subnetwork_id
|
||||
}
|
||||
network_config = {
|
||||
ip_cidr_node = module.stackit_infrastructure.ip_cidr_node
|
||||
ip_cidr_service = "10.96.0.0/12"
|
||||
}
|
||||
}
|
||||
|
||||
output "kubeconfig" {
|
||||
value = constellation_cluster.stackit_example.kubeconfig
|
||||
sensitive = true
|
||||
description = "KubeConfig for the Constellation cluster."
|
||||
}
|
@ -23,6 +23,8 @@ go_library(
|
||||
"//internal/attestation/variant",
|
||||
"//internal/cloud/azureshared",
|
||||
"//internal/cloud/cloudprovider",
|
||||
"//internal/cloud/openstack",
|
||||
"//internal/cloud/openstack/clouds",
|
||||
"//internal/compatibility",
|
||||
"//internal/config",
|
||||
"//internal/constants",
|
||||
@ -30,6 +32,7 @@ go_library(
|
||||
"//internal/constellation/helm",
|
||||
"//internal/constellation/kubecmd",
|
||||
"//internal/constellation/state",
|
||||
"//internal/file",
|
||||
"//internal/grpc/dialer",
|
||||
"//internal/imagefetcher",
|
||||
"//internal/kms/uri",
|
||||
@ -53,6 +56,7 @@ go_library(
|
||||
"@com_github_hashicorp_terraform_plugin_framework//types/basetypes",
|
||||
"@com_github_hashicorp_terraform_plugin_framework_validators//stringvalidator",
|
||||
"@com_github_hashicorp_terraform_plugin_log//tflog",
|
||||
"@com_github_spf13_afero//:afero",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -110,6 +110,58 @@ func TestAccAttestationSource(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"STACKIT qemu-vtpm success": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_attestation" "test" {
|
||||
csp = "stackit"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
image = {
|
||||
version = "v2.13.0"
|
||||
reference = "v2.13.0"
|
||||
short_path = "v2.13.0"
|
||||
}
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.variant", "qemu-vtpm"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.bootloader_version", "0"), // since this is not supported on STACKIT, we expect 0
|
||||
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.measurements.15.expected", "0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.measurements.15.warn_only", "false"),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
"openstack qemu-vtpm success": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testingConfig + `
|
||||
data "constellation_attestation" "test" {
|
||||
csp = "openstack"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
image = {
|
||||
version = "v2.13.0"
|
||||
reference = "v2.13.0"
|
||||
short_path = "v2.13.0"
|
||||
}
|
||||
}
|
||||
`,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.variant", "qemu-vtpm"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.bootloader_version", "0"), // since this is not supported on OpenStack, we expect 0
|
||||
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.measurements.15.expected", "0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
resource.TestCheckResourceAttr("data.constellation_attestation.test", "attestation.measurements.15.warn_only", "false"),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
|
@ -26,6 +26,8 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/azureshared"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
openstackshared "github.com/edgelesssys/constellation/v2/internal/cloud/openstack"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/openstack/clouds"
|
||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||
@ -33,6 +35,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/helm"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/kubecmd"
|
||||
"github.com/edgelesssys/constellation/v2/internal/constellation/state"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
"github.com/edgelesssys/constellation/v2/internal/grpc/dialer"
|
||||
"github.com/edgelesssys/constellation/v2/internal/kms/uri"
|
||||
"github.com/edgelesssys/constellation/v2/internal/license"
|
||||
@ -50,6 +53,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -96,6 +100,7 @@ type ClusterResourceModel struct {
|
||||
Attestation types.Object `tfsdk:"attestation"`
|
||||
GCP types.Object `tfsdk:"gcp"`
|
||||
Azure types.Object `tfsdk:"azure"`
|
||||
OpenStack types.Object `tfsdk:"openstack"`
|
||||
|
||||
OwnerID types.String `tfsdk:"owner_id"`
|
||||
ClusterID types.String `tfsdk:"cluster_id"`
|
||||
@ -129,6 +134,17 @@ type azureAttribute struct {
|
||||
LoadBalancerName string `tfsdk:"load_balancer_name"`
|
||||
}
|
||||
|
||||
type openStackAttribute struct {
|
||||
Cloud string `tfsdk:"cloud"`
|
||||
CloudsYAMLPath string `tfsdk:"clouds_yaml_path"`
|
||||
FloatingIPPoolID string `tfsdk:"floating_ip_pool_id"`
|
||||
DeployYawolLoadBalancer bool `tfsdk:"deploy_yawol_load_balancer"`
|
||||
YawolImageID string `tfsdk:"yawol_image_id"`
|
||||
YawolFlavorID string `tfsdk:"yawol_flavor_id"`
|
||||
NetworkID string `tfsdk:"network_id"`
|
||||
SubnetID string `tfsdk:"subnet_id"`
|
||||
}
|
||||
|
||||
// extraMicroservicesAttribute is the extra microservices attribute's data model.
|
||||
type extraMicroservicesAttribute struct {
|
||||
CSIDriver bool `tfsdk:"csi_driver"`
|
||||
@ -333,6 +349,53 @@ func (r *ClusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
|
||||
},
|
||||
},
|
||||
},
|
||||
"openstack": schema.SingleNestedAttribute{
|
||||
MarkdownDescription: "OpenStack-specific configuration.",
|
||||
Description: "OpenStack-specific configuration.",
|
||||
Optional: true,
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"cloud": schema.StringAttribute{
|
||||
MarkdownDescription: "Name of the cloud in the clouds.yaml file.",
|
||||
Description: "Name of the cloud in the clouds.yaml file.",
|
||||
Required: true,
|
||||
},
|
||||
"clouds_yaml_path": schema.StringAttribute{
|
||||
MarkdownDescription: "Path to the clouds.yaml file.",
|
||||
Description: "Path to the clouds.yaml file.",
|
||||
Optional: true,
|
||||
},
|
||||
"floating_ip_pool_id": schema.StringAttribute{
|
||||
MarkdownDescription: "Floating IP pool to use for the VMs.",
|
||||
Description: "Floating IP pool to use for the VMs.",
|
||||
Required: true,
|
||||
},
|
||||
"deploy_yawol_load_balancer": schema.BoolAttribute{
|
||||
MarkdownDescription: "Whether to deploy a YAWOL load balancer.",
|
||||
Description: "Whether to deploy a YAWOL load balancer.",
|
||||
Optional: true,
|
||||
},
|
||||
"yawol_image_id": schema.StringAttribute{
|
||||
MarkdownDescription: "OpenStack OS image used by the yawollet.",
|
||||
Description: "OpenStack OS image used by the yawollet.",
|
||||
Optional: true,
|
||||
},
|
||||
"yawol_flavor_id": schema.StringAttribute{
|
||||
MarkdownDescription: "OpenStack flavor used by the yawollet.",
|
||||
Description: "OpenStack flavor used by the yawollet.",
|
||||
Optional: true,
|
||||
},
|
||||
"network_id": schema.StringAttribute{
|
||||
MarkdownDescription: "OpenStack network ID to use for the VMs.",
|
||||
Description: "OpenStack network ID to use for the VMs.",
|
||||
Required: true,
|
||||
},
|
||||
"subnet_id": schema.StringAttribute{
|
||||
MarkdownDescription: "OpenStack subnet ID to use for the VMs.",
|
||||
Description: "OpenStack subnet ID to use for the VMs.",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Computed (output) attributes
|
||||
"owner_id": schema.StringAttribute{
|
||||
@ -406,6 +469,26 @@ func (r *ClusterResource) ValidateConfig(ctx context.Context, req resource.Valid
|
||||
"GCP configuration not allowed", "When csp is not set to 'gcp', setting the 'gcp' configuration has no effect.",
|
||||
)
|
||||
}
|
||||
|
||||
// OpenStack Config is required for OpenStack
|
||||
if (strings.EqualFold(data.CSP.ValueString(), cloudprovider.OpenStack.String()) ||
|
||||
strings.EqualFold(data.CSP.ValueString(), "stackit")) &&
|
||||
data.OpenStack.IsNull() {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
path.Root("openstack"),
|
||||
"OpenStack configuration missing", "When csp is set to 'openstack' or 'stackit', the 'openstack' configuration must be set.",
|
||||
)
|
||||
}
|
||||
|
||||
// OpenStack Config should not be set for other CSPs
|
||||
if !strings.EqualFold(data.CSP.ValueString(), cloudprovider.OpenStack.String()) &&
|
||||
!strings.EqualFold(data.CSP.ValueString(), "stackit") &&
|
||||
!data.OpenStack.IsNull() {
|
||||
resp.Diagnostics.AddAttributeWarning(
|
||||
path.Root("openstack"),
|
||||
"OpenStack configuration not allowed", "When csp is not set to 'openstack' or 'stackit', setting the 'openstack' configuration has no effect.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Configure configures the resource.
|
||||
@ -447,28 +530,31 @@ func (r *ClusterResource) ModifyPlan(ctx context.Context, req resource.ModifyPla
|
||||
return
|
||||
}
|
||||
|
||||
licenseID := plannedState.LicenseID.ValueString()
|
||||
if licenseID == "" {
|
||||
resp.Diagnostics.AddWarning("Constellation license ID not set.",
|
||||
"Continuing with community license.")
|
||||
}
|
||||
if licenseID == license.CommunityLicense {
|
||||
resp.Diagnostics.AddWarning("Using community license.",
|
||||
"For details, see https://docs.edgeless.systems/constellation/overview/license")
|
||||
}
|
||||
|
||||
// Validate during plan. Must be done in ModifyPlan to read provider data.
|
||||
// See https://developer.hashicorp.com/terraform/plugin/framework/resources/configure#define-resource-configure-method.
|
||||
_, diags := r.getMicroserviceVersion(&plannedState)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
_, _, diags = r.getImageVersion(ctx, &plannedState)
|
||||
var image imageAttribute
|
||||
image, _, diags = r.getImageVersion(ctx, &plannedState)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
licenseID := plannedState.LicenseID.ValueString()
|
||||
switch {
|
||||
case image.MarketplaceImage != nil && *image.MarketplaceImage:
|
||||
// Marketplace images do not require a license.
|
||||
case licenseID == "":
|
||||
resp.Diagnostics.AddWarning("Constellation license ID not set.",
|
||||
"Continuing with community license.")
|
||||
case licenseID == license.CommunityLicense:
|
||||
resp.Diagnostics.AddWarning("Using community license.",
|
||||
"For details, see https://docs.edgeless.systems/constellation/overview/license")
|
||||
}
|
||||
|
||||
// Checks running on updates to the resource. (i.e. state and plan != nil)
|
||||
if !req.State.Raw.IsNull() {
|
||||
// Read currentState supplied by Terraform runtime into the model
|
||||
@ -759,9 +845,13 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
|
||||
// parse license ID
|
||||
licenseID := data.LicenseID.ValueString()
|
||||
if licenseID == "" {
|
||||
switch {
|
||||
case image.MarketplaceImage != nil && *image.MarketplaceImage:
|
||||
licenseID = license.MarketplaceLicense
|
||||
case licenseID == "":
|
||||
licenseID = license.CommunityLicense
|
||||
}
|
||||
|
||||
// license ID can be base64-encoded
|
||||
licenseIDFromB64, err := base64.StdEncoding.DecodeString(licenseID)
|
||||
if err == nil {
|
||||
@ -772,6 +862,7 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
serviceAccPayload := constellation.ServiceAccountPayload{}
|
||||
var gcpConfig gcpAttribute
|
||||
var azureConfig azureAttribute
|
||||
var openStackConfig openStackAttribute
|
||||
switch csp {
|
||||
case cloudprovider.GCP:
|
||||
convertDiags = data.GCP.As(ctx, &gcpConfig, basetypes.ObjectAsOptions{})
|
||||
@ -808,6 +899,33 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
PreferredAuthMethod: azureshared.AuthMethodUserAssignedIdentity,
|
||||
UamiResourceID: azureConfig.UamiResourceID,
|
||||
}
|
||||
case cloudprovider.OpenStack:
|
||||
convertDiags = data.OpenStack.As(ctx, &openStackConfig, basetypes.ObjectAsOptions{})
|
||||
diags.Append(convertDiags...)
|
||||
if diags.HasError() {
|
||||
return diags
|
||||
}
|
||||
cloudsYAML, err := clouds.ReadCloudsYAML(file.NewHandler(afero.NewOsFs()), openStackConfig.CloudsYAMLPath)
|
||||
if err != nil {
|
||||
diags.AddError("Reading clouds.yaml", err.Error())
|
||||
return diags
|
||||
}
|
||||
cloud, ok := cloudsYAML.Clouds[openStackConfig.Cloud]
|
||||
if !ok {
|
||||
diags.AddError("Reading clouds.yaml", fmt.Sprintf("Cloud %s not found in clouds.yaml", openStackConfig.Cloud))
|
||||
return diags
|
||||
}
|
||||
serviceAccPayload.OpenStack = openstackshared.AccountKey{
|
||||
AuthURL: cloud.AuthInfo.AuthURL,
|
||||
Username: cloud.AuthInfo.Username,
|
||||
Password: cloud.AuthInfo.Password,
|
||||
ProjectID: cloud.AuthInfo.ProjectID,
|
||||
ProjectName: cloud.AuthInfo.ProjectName,
|
||||
UserDomainName: cloud.AuthInfo.UserDomainName,
|
||||
ProjectDomainName: cloud.AuthInfo.ProjectDomainName,
|
||||
RegionName: cloud.RegionName,
|
||||
}
|
||||
|
||||
}
|
||||
serviceAccURI, err := constellation.MarshalServiceAccountURI(csp, serviceAccPayload)
|
||||
if err != nil {
|
||||
@ -854,6 +972,11 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
ProjectID: gcpConfig.ProjectID,
|
||||
IPCidrPod: networkCfg.IPCidrPod.ValueString(),
|
||||
}
|
||||
case cloudprovider.OpenStack:
|
||||
stateFile.Infrastructure.OpenStack = &state.OpenStack{
|
||||
NetworkID: openStackConfig.NetworkID,
|
||||
SubnetID: openStackConfig.SubnetID,
|
||||
}
|
||||
}
|
||||
|
||||
// Check license
|
||||
@ -930,6 +1053,14 @@ func (r *ClusterResource) apply(ctx context.Context, data *ClusterResourceModel,
|
||||
masterSecret: secrets.masterSecret,
|
||||
serviceAccURI: serviceAccURI,
|
||||
}
|
||||
if csp == cloudprovider.OpenStack {
|
||||
payload.openStackHelmValues = &helm.OpenStackValues{
|
||||
DeployYawolLoadBalancer: openStackConfig.DeployYawolLoadBalancer,
|
||||
FloatingIPPoolID: openStackConfig.FloatingIPPoolID,
|
||||
YawolImageID: openStackConfig.YawolImageID,
|
||||
YawolFlavorID: openStackConfig.YawolFlavorID,
|
||||
}
|
||||
}
|
||||
helmDiags := r.applyHelmCharts(ctx, applier, payload, stateFile)
|
||||
diags.Append(helmDiags...)
|
||||
if diags.HasError() {
|
||||
@ -1056,6 +1187,7 @@ type applyHelmChartsPayload struct {
|
||||
DeployCSIDriver bool // Whether to deploy the CSI driver.
|
||||
masterSecret uri.MasterSecret // master secret of the cluster.
|
||||
serviceAccURI string // URI of the service account used within the cluster.
|
||||
openStackHelmValues *helm.OpenStackValues // OpenStack-specific Helm values.
|
||||
}
|
||||
|
||||
// applyHelmCharts applies the Helm charts to the cluster.
|
||||
@ -1076,10 +1208,11 @@ func (r *ClusterResource) applyHelmCharts(ctx context.Context, applier *constell
|
||||
// Allow destructive changes to the cluster.
|
||||
// The user has previously been warned about this when planning a microservice version change.
|
||||
AllowDestructive: helm.AllowDestructive,
|
||||
OpenStackValues: payload.openStackHelmValues,
|
||||
}
|
||||
|
||||
executor, _, err := applier.PrepareHelmCharts(options, state,
|
||||
payload.serviceAccURI, payload.masterSecret, nil)
|
||||
payload.serviceAccURI, payload.masterSecret)
|
||||
var upgradeErr *compatibility.InvalidUpgradeError
|
||||
if err != nil {
|
||||
if !errors.As(err, &upgradeErr) {
|
||||
|
@ -97,9 +97,10 @@ func TestViolatedImageConstraint(t *testing.T) {
|
||||
}
|
||||
|
||||
input, diags := basetypes.NewObjectValueFrom(context.Background(), map[string]attr.Type{
|
||||
"version": basetypes.StringType{},
|
||||
"reference": basetypes.StringType{},
|
||||
"short_path": basetypes.StringType{},
|
||||
"version": basetypes.StringType{},
|
||||
"reference": basetypes.StringType{},
|
||||
"short_path": basetypes.StringType{},
|
||||
"marketplace_image": basetypes.BoolType{},
|
||||
}, img)
|
||||
require.Equal(t, 0, diags.ErrorsCount())
|
||||
_, _, diags2 := sut.getImageVersion(context.Background(), &ClusterResourceModel{
|
||||
@ -488,6 +489,68 @@ func TestAccClusterResource(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"stackit config missing": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactoriesWithVersion(providerVersion),
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: fullClusterTestingConfig(t, "openstack") + fmt.Sprintf(`
|
||||
resource "constellation_cluster" "test" {
|
||||
csp = "stackit"
|
||||
name = "constell"
|
||||
uid = "test"
|
||||
image = data.constellation_image.bar.image
|
||||
attestation = data.constellation_attestation.foo.attestation
|
||||
init_secret = "deadbeef"
|
||||
master_secret = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
master_secret_salt = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
measurement_salt = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
out_of_cluster_endpoint = "192.0.2.1"
|
||||
in_cluster_endpoint = "192.0.2.1"
|
||||
network_config = {
|
||||
ip_cidr_node = "0.0.0.0/24"
|
||||
ip_cidr_service = "0.0.0.0/24"
|
||||
ip_cidr_pod = "0.0.0.0/24"
|
||||
}
|
||||
kubernetes_version = "%s"
|
||||
constellation_microservice_version = "%s"
|
||||
}
|
||||
`, versions.Default, providerVersion),
|
||||
ExpectError: regexp.MustCompile(".*When csp is set to 'openstack' or 'stackit', the 'openstack' configuration\nmust be set.*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
"openstack config missing": {
|
||||
ProtoV6ProviderFactories: testAccProtoV6ProviderFactoriesWithVersion(providerVersion),
|
||||
PreCheck: bazelPreCheck,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: fullClusterTestingConfig(t, "openstack") + fmt.Sprintf(`
|
||||
resource "constellation_cluster" "test" {
|
||||
csp = "openstack"
|
||||
name = "constell"
|
||||
uid = "test"
|
||||
image = data.constellation_image.bar.image
|
||||
attestation = data.constellation_attestation.foo.attestation
|
||||
init_secret = "deadbeef"
|
||||
master_secret = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
master_secret_salt = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
measurement_salt = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
|
||||
out_of_cluster_endpoint = "192.0.2.1"
|
||||
in_cluster_endpoint = "192.0.2.1"
|
||||
network_config = {
|
||||
ip_cidr_node = "0.0.0.0/24"
|
||||
ip_cidr_service = "0.0.0.0/24"
|
||||
ip_cidr_pod = "0.0.0.0/24"
|
||||
}
|
||||
kubernetes_version = "%s"
|
||||
constellation_microservice_version = "%s"
|
||||
}
|
||||
`, versions.Default, providerVersion),
|
||||
ExpectError: regexp.MustCompile(".*When csp is set to 'openstack' or 'stackit', the 'openstack' configuration\nmust be set.*"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
@ -546,6 +609,19 @@ func fullClusterTestingConfig(t *testing.T, csp string) string {
|
||||
attestation_variant = "gcp-sev-es"
|
||||
image = data.constellation_image.bar.image
|
||||
}`, image)
|
||||
case "openstack":
|
||||
return providerConfig + fmt.Sprintf(`
|
||||
data "constellation_image" "bar" {
|
||||
version = "%s"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
csp = "openstack"
|
||||
}
|
||||
|
||||
data "constellation_attestation" "foo" {
|
||||
csp = "openstack"
|
||||
attestation_variant = "qemu-vtpm"
|
||||
image = data.constellation_image.bar.image
|
||||
}`, image)
|
||||
default:
|
||||
t.Fatal("unknown csp")
|
||||
return ""
|
||||
|
@ -122,6 +122,10 @@ func convertFromTfAttestationCfg(tfAttestation attestationAttribute, attestation
|
||||
attestationConfig = &config.GCPSEVES{
|
||||
Measurements: c11nMeasurements,
|
||||
}
|
||||
case variant.QEMUVTPM{}:
|
||||
attestationConfig = &config.QEMUVTPM{
|
||||
Measurements: c11nMeasurements,
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown attestation variant: %s", attestationVariant)
|
||||
}
|
||||
@ -177,7 +181,7 @@ func convertToTfAttestation(attVar variant.Variant, snpVersions attestationconfi
|
||||
XFAM: hex.EncodeToString(tdxCfg.XFAM),
|
||||
}
|
||||
tfAttestation.TDX = tfTdxCfg
|
||||
case variant.GCPSEVES{}:
|
||||
case variant.GCPSEVES{}, variant.QEMUVTPM{}:
|
||||
// no additional fields
|
||||
default:
|
||||
return tfAttestation, fmt.Errorf("unknown attestation variant: %s", attVar)
|
||||
|
@ -252,9 +252,10 @@ func (d *ImageDataSource) Read(ctx context.Context, req datasource.ReadRequest,
|
||||
|
||||
// Save data into Terraform state
|
||||
diags := resp.State.SetAttribute(ctx, path.Root("image"), imageAttribute{
|
||||
Reference: imageRef,
|
||||
Version: imageSemver,
|
||||
ShortPath: apiCompatibleVer.ShortPath(),
|
||||
Reference: imageRef,
|
||||
Version: imageSemver,
|
||||
ShortPath: apiCompatibleVer.ShortPath(),
|
||||
MarketplaceImage: data.MarketplaceImage.ValueBoolPointer(),
|
||||
})
|
||||
resp.Diagnostics.Append(diags...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user