mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-02-12 21:11:26 -05:00
feat: status
shows attestation config (#2056)
* init * update doc * fix tests * unmarshal typed attestation config for consistent yaml formatting * fix comments * marshal numerical attestation values in join-config * GetAttestationConfig marshals numerical value
This commit is contained in:
parent
fafafb48d7
commit
7e83991154
@ -85,6 +85,7 @@ go_library(
|
|||||||
"@com_github_siderolabs_talos_pkg_machinery//config/encoder",
|
"@com_github_siderolabs_talos_pkg_machinery//config/encoder",
|
||||||
"@com_github_spf13_afero//:afero",
|
"@com_github_spf13_afero//:afero",
|
||||||
"@com_github_spf13_cobra//:cobra",
|
"@com_github_spf13_cobra//:cobra",
|
||||||
|
"@in_gopkg_yaml_v3//:yaml_v3",
|
||||||
"@io_k8s_api//core/v1:core",
|
"@io_k8s_api//core/v1:core",
|
||||||
"@io_k8s_apimachinery//pkg/runtime",
|
"@io_k8s_apimachinery//pkg/runtime",
|
||||||
"@io_k8s_client_go//dynamic",
|
"@io_k8s_client_go//dynamic",
|
||||||
|
@ -8,17 +8,22 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
"github.com/edgelesssys/constellation/v2/cli/internal/kubernetes"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
|
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
|
||||||
"github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
"github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
@ -74,7 +79,25 @@ func runStatus(cmd *cobra.Command, _ []string) error {
|
|||||||
return fmt.Errorf("setting up helm client: %w", err)
|
return fmt.Errorf("setting up helm client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := status(cmd.Context(), kubeClient, helmClient, kubernetes.NewNodeVersionClient(unstructuredClient))
|
stableClient := kubernetes.NewStableClient(kubeClient)
|
||||||
|
|
||||||
|
configPath, err := cmd.Flags().GetString("config")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting config flag: %w", err)
|
||||||
|
}
|
||||||
|
force, err := cmd.Flags().GetBool("force")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting config flag: %w", err)
|
||||||
|
}
|
||||||
|
fetcher := attestationconfigapi.NewFetcher()
|
||||||
|
conf, err := config.New(fileHandler, configPath, fetcher, force)
|
||||||
|
var configValidationErr *config.ValidationError
|
||||||
|
if errors.As(err, &configValidationErr) {
|
||||||
|
cmd.PrintErrln(configValidationErr.LongMessage())
|
||||||
|
}
|
||||||
|
variant := conf.GetAttestationConfig().GetVariant()
|
||||||
|
|
||||||
|
output, err := status(cmd.Context(), kubeClient, stableClient, helmClient, kubernetes.NewNodeVersionClient(unstructuredClient), variant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting status: %w", err)
|
return fmt.Errorf("getting status: %w", err)
|
||||||
}
|
}
|
||||||
@ -84,7 +107,7 @@ func runStatus(cmd *cobra.Command, _ []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// status queries the cluster for the relevant status information and returns the output string.
|
// status queries the cluster for the relevant status information and returns the output string.
|
||||||
func status(ctx context.Context, kubeClient kubeClient, helmClient helmClient, dynamicInterface kubernetes.DynamicInterface) (string, error) {
|
func status(ctx context.Context, kubeClient kubeClient, cmClient configMapClient, helmClient helmClient, dynamicInterface kubernetes.DynamicInterface, attestVariant variant.Variant) (string, error) {
|
||||||
nodeVersion, err := kubernetes.GetConstellationVersion(ctx, dynamicInterface)
|
nodeVersion, err := kubernetes.GetConstellationVersion(ctx, dynamicInterface)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("getting constellation version: %w", err)
|
return "", fmt.Errorf("getting constellation version: %w", err)
|
||||||
@ -93,6 +116,24 @@ func status(ctx context.Context, kubeClient kubeClient, helmClient helmClient, d
|
|||||||
return "", fmt.Errorf("expected exactly one condition, got %d", len(nodeVersion.Status.Conditions))
|
return "", fmt.Errorf("expected exactly one condition, got %d", len(nodeVersion.Status.Conditions))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// attestation version
|
||||||
|
joinConfig, err := cmClient.GetCurrentConfigMap(ctx, constants.JoinConfigMap)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("getting current config map: %w", err)
|
||||||
|
}
|
||||||
|
rawAttestationConfig, ok := joinConfig.Data[constants.AttestationConfigFilename]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("attestationConfig not found in %s", constants.JoinConfigMap)
|
||||||
|
}
|
||||||
|
attestationConfig, err := config.UnmarshalAttestationConfig([]byte(rawAttestationConfig), attestVariant)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unmarshalling attestation config: %w", err)
|
||||||
|
}
|
||||||
|
prettyYAML, err := yaml.Marshal(attestationConfig)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("marshalling attestation config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
targetVersions, err := kubernetes.NewTargetVersions(nodeVersion)
|
targetVersions, err := kubernetes.NewTargetVersions(nodeVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("getting configured versions: %w", err)
|
return "", fmt.Errorf("getting configured versions: %w", err)
|
||||||
@ -108,21 +149,29 @@ func status(ctx context.Context, kubeClient kubeClient, helmClient helmClient, d
|
|||||||
return "", fmt.Errorf("getting cluster status: %w", err)
|
return "", fmt.Errorf("getting cluster status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return statusOutput(targetVersions, serviceVersions, status, nodeVersion), nil
|
return statusOutput(targetVersions, serviceVersions, status, nodeVersion, string(prettyYAML)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// statusOutput creates the status cmd output string by formatting the received information.
|
// statusOutput creates the status cmd output string by formatting the received information.
|
||||||
func statusOutput(targetVersions kubernetes.TargetVersions, serviceVersions helm.ServiceVersions, status map[string]kubernetes.NodeStatus, nodeVersion v1alpha1.NodeVersion) string {
|
func statusOutput(targetVersions kubernetes.TargetVersions, serviceVersions helm.ServiceVersions, status map[string]kubernetes.NodeStatus, nodeVersion v1alpha1.NodeVersion, rawAttestationConfig string) string {
|
||||||
builder := strings.Builder{}
|
builder := strings.Builder{}
|
||||||
|
|
||||||
builder.WriteString(targetVersionsString(targetVersions))
|
builder.WriteString(targetVersionsString(targetVersions))
|
||||||
builder.WriteString(serviceVersionsString(serviceVersions))
|
builder.WriteString(serviceVersionsString(serviceVersions))
|
||||||
builder.WriteString(fmt.Sprintf("Cluster status: %s\n", nodeVersion.Status.Conditions[0].Message))
|
builder.WriteString(fmt.Sprintf("Cluster status: %s\n", nodeVersion.Status.Conditions[0].Message))
|
||||||
builder.WriteString(nodeStatusString(status, targetVersions))
|
builder.WriteString(nodeStatusString(status, targetVersions))
|
||||||
|
builder.WriteString(fmt.Sprintf("Attestation config:\n%s", indentEntireStringWithTab(rawAttestationConfig)))
|
||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func indentEntireStringWithTab(input string) string {
|
||||||
|
lines := strings.Split(input, "\n")
|
||||||
|
for i, line := range lines[:len(lines)-1] {
|
||||||
|
lines[i] = "\t" + line
|
||||||
|
}
|
||||||
|
return strings.Join(lines, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
// nodeStatusString creates the node status part of the output string.
|
// nodeStatusString creates the node status part of the output string.
|
||||||
func nodeStatusString(status map[string]kubernetes.NodeStatus, targetVersions kubernetes.TargetVersions) string {
|
func nodeStatusString(status map[string]kubernetes.NodeStatus, targetVersions kubernetes.TargetVersions) string {
|
||||||
var upToDateImages int
|
var upToDateImages int
|
||||||
@ -170,6 +219,9 @@ type kubeClient interface {
|
|||||||
GetNodes(ctx context.Context) ([]corev1.Node, error)
|
GetNodes(ctx context.Context) ([]corev1.Node, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type configMapClient interface {
|
||||||
|
GetCurrentConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error)
|
||||||
|
}
|
||||||
type helmClient interface {
|
type helmClient interface {
|
||||||
Versions() (helm.ServiceVersions, error)
|
Versions() (helm.ServiceVersions, error)
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||||
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -29,7 +30,7 @@ Installed service versions:
|
|||||||
constellation-operators: v1.1.0
|
constellation-operators: v1.1.0
|
||||||
constellation-services: v1.1.0
|
constellation-services: v1.1.0
|
||||||
Cluster status: Node version of every node is up to date
|
Cluster status: Node version of every node is up to date
|
||||||
`
|
` + attestationConfigOutput
|
||||||
|
|
||||||
const inProgressOutput = `Target versions:
|
const inProgressOutput = `Target versions:
|
||||||
Image: v1.1.0
|
Image: v1.1.0
|
||||||
@ -42,6 +43,49 @@ Installed service versions:
|
|||||||
Cluster status: Some node versions are out of date
|
Cluster status: Some node versions are out of date
|
||||||
Image: 1/2
|
Image: 1/2
|
||||||
Kubernetes: 1/2
|
Kubernetes: 1/2
|
||||||
|
` + attestationConfigOutput
|
||||||
|
|
||||||
|
const attestationConfigOutput = `Attestation config:
|
||||||
|
measurements:
|
||||||
|
0:
|
||||||
|
expected: 737f767a12f54e70eecbc8684011323ae2fe2dd9f90785577969d7a2013e8c12
|
||||||
|
warnOnly: true
|
||||||
|
2:
|
||||||
|
expected: 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
|
||||||
|
warnOnly: true
|
||||||
|
3:
|
||||||
|
expected: 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
|
||||||
|
warnOnly: true
|
||||||
|
4:
|
||||||
|
expected: 55f7616b2c51dd7603f491c1c266373fe5c1e25e06a851d2090960172b03b27f
|
||||||
|
warnOnly: false
|
||||||
|
6:
|
||||||
|
expected: 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
|
||||||
|
warnOnly: true
|
||||||
|
7:
|
||||||
|
expected: fb71e5e55cefba9e2b396d17604de0fe6e1841a76758856a120833e3ad1c40a3
|
||||||
|
warnOnly: true
|
||||||
|
8:
|
||||||
|
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
warnOnly: false
|
||||||
|
9:
|
||||||
|
expected: f7480d37929bef4b61c32823cb7b3771aea19f7510db2e1478719a1d88f9775d
|
||||||
|
warnOnly: false
|
||||||
|
11:
|
||||||
|
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
warnOnly: false
|
||||||
|
12:
|
||||||
|
expected: b8038d11eade4cfee5fd41da04bf64e58bab15c42bfe01801e4c0f61376ba010
|
||||||
|
warnOnly: false
|
||||||
|
13:
|
||||||
|
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
warnOnly: false
|
||||||
|
14:
|
||||||
|
expected: d7c4cc7ff7933022f013e03bdee875b91720b5b86cf1753cad830f95e791926f
|
||||||
|
warnOnly: true
|
||||||
|
15:
|
||||||
|
expected: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
warnOnly: false
|
||||||
`
|
`
|
||||||
|
|
||||||
// TestStatus checks that the status function produces the correct strings.
|
// TestStatus checks that the status function produces the correct strings.
|
||||||
@ -150,7 +194,9 @@ func TestStatus(t *testing.T) {
|
|||||||
|
|
||||||
raw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.nodeVersion)
|
raw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.nodeVersion)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
output, err := status(context.Background(), tc.kubeClient, tc.helmClient, &stubDynamicInterface{data: unstructured.Unstructured{Object: raw}, err: tc.dynamicErr})
|
configMapper := stubConfigMapperAWSNitro{}
|
||||||
|
variant := variant.AWSNitroTPM{}
|
||||||
|
output, err := status(context.Background(), tc.kubeClient, configMapper, tc.helmClient, &stubDynamicInterface{data: unstructured.Unstructured{Object: raw}, err: tc.dynamicErr}, variant)
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
return
|
return
|
||||||
@ -161,6 +207,16 @@ func TestStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stubConfigMapperAWSNitro struct{}
|
||||||
|
|
||||||
|
func (s stubConfigMapperAWSNitro) GetCurrentConfigMap(_ context.Context, _ string) (*corev1.ConfigMap, error) {
|
||||||
|
return &corev1.ConfigMap{
|
||||||
|
Data: map[string]string{
|
||||||
|
"attestationConfig": `{"measurements":{"0":{"expected":"737f767a12f54e70eecbc8684011323ae2fe2dd9f90785577969d7a2013e8c12","warnOnly":true},"11":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false},"12":{"expected":"b8038d11eade4cfee5fd41da04bf64e58bab15c42bfe01801e4c0f61376ba010","warnOnly":false},"13":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false},"14":{"expected":"d7c4cc7ff7933022f013e03bdee875b91720b5b86cf1753cad830f95e791926f","warnOnly":true},"15":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false},"2":{"expected":"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969","warnOnly":true},"3":{"expected":"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969","warnOnly":true},"4":{"expected":"55f7616b2c51dd7603f491c1c266373fe5c1e25e06a851d2090960172b03b27f","warnOnly":false},"6":{"expected":"3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969","warnOnly":true},"7":{"expected":"fb71e5e55cefba9e2b396d17604de0fe6e1841a76758856a120833e3ad1c40a3","warnOnly":true},"8":{"expected":"0000000000000000000000000000000000000000000000000000000000000000","warnOnly":false},"9":{"expected":"f7480d37929bef4b61c32823cb7b3771aea19f7510db2e1478719a1d88f9775d","warnOnly":false}}}`,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type stubKubeClient struct {
|
type stubKubeClient struct {
|
||||||
nodes []corev1.Node
|
nodes []corev1.Node
|
||||||
err error
|
err error
|
||||||
|
@ -84,6 +84,10 @@ func TestConstellationServices(t *testing.T) {
|
|||||||
EnforcementPolicy: idkeydigest.MAAFallback,
|
EnforcementPolicy: idkeydigest.MAAFallback,
|
||||||
MAAURL: "https://192.0.2.1:8080/maa",
|
MAAURL: "https://192.0.2.1:8080/maa",
|
||||||
},
|
},
|
||||||
|
BootloaderVersion: config.AttestationVersion{Value: 1, WantLatest: true},
|
||||||
|
TEEVersion: config.AttestationVersion{Value: 2, WantLatest: true},
|
||||||
|
SNPVersion: config.AttestationVersion{Value: 3, WantLatest: true},
|
||||||
|
MicrocodeVersion: config.AttestationVersion{Value: 4, WantLatest: true},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
enforceIDKeyDigest: true,
|
enforceIDKeyDigest: true,
|
||||||
@ -175,7 +179,7 @@ func TestConstellationServices(t *testing.T) {
|
|||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
testDataPath := path.Join("testdata", tc.config.GetProvider().String(), "constellation-services")
|
testDataPath := path.Join("testdata", tc.config.GetProvider().String(), "constellation-services")
|
||||||
|
|
||||||
// Build a map with the same structe as result: filepaths -> rendered template.
|
// Build a map with the same struct as result: filepaths -> rendered template.
|
||||||
expectedData := map[string]string{}
|
expectedData := map[string]string{}
|
||||||
err = filepath.Walk(testDataPath, buildTestdataMap(tc.config.GetProvider().String(), expectedData, require))
|
err = filepath.Walk(testDataPath, buildTestdataMap(tc.config.GetProvider().String(), expectedData, require))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
@ -4,6 +4,6 @@ metadata:
|
|||||||
name: join-config
|
name: join-config
|
||||||
namespace: testNamespace
|
namespace: testNamespace
|
||||||
data:
|
data:
|
||||||
attestationConfig: "{\"measurements\":{\"1\":{\"expected\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"warnOnly\":false}},\"bootloaderVersion\":0,\"teeVersion\":0,\"snpVersion\":0,\"microcodeVersion\":0,\"firmwareSignerConfig\":{\"acceptedKeyDigests\":[\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"],\"enforcementPolicy\":\"MAAFallback\",\"maaURL\":\"https://192.0.2.1:8080/maa\"},\"amdRootKey\":\"-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n\"}"
|
attestationConfig: "{\"measurements\":{\"1\":{\"expected\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"warnOnly\":false}},\"bootloaderVersion\":1,\"teeVersion\":2,\"snpVersion\":3,\"microcodeVersion\":4,\"firmwareSignerConfig\":{\"acceptedKeyDigests\":[\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"],\"enforcementPolicy\":\"MAAFallback\",\"maaURL\":\"https://192.0.2.1:8080/maa\"},\"amdRootKey\":\"-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n\"}"
|
||||||
binaryData:
|
binaryData:
|
||||||
measurementSalt: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
measurementSalt: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
@ -89,7 +89,7 @@ func (e *applyError) Error() string {
|
|||||||
|
|
||||||
// Upgrader handles upgrading the cluster's components using the CLI.
|
// Upgrader handles upgrading the cluster's components using the CLI.
|
||||||
type Upgrader struct {
|
type Upgrader struct {
|
||||||
stableInterface stableInterface
|
stableInterface StableInterface
|
||||||
dynamicInterface DynamicInterface
|
dynamicInterface DynamicInterface
|
||||||
helmClient helmInterface
|
helmClient helmInterface
|
||||||
imageFetcher imageFetcher
|
imageFetcher imageFetcher
|
||||||
@ -275,7 +275,7 @@ func (u *Upgrader) UpgradeNodeVersion(ctx context.Context, conf *config.Config,
|
|||||||
|
|
||||||
// KubernetesVersion returns the version of Kubernetes the Constellation is currently running on.
|
// KubernetesVersion returns the version of Kubernetes the Constellation is currently running on.
|
||||||
func (u *Upgrader) KubernetesVersion() (string, error) {
|
func (u *Upgrader) KubernetesVersion() (string, error) {
|
||||||
return u.stableInterface.kubernetesVersion()
|
return u.stableInterface.KubernetesVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentImage returns the currently used image version of the cluster.
|
// CurrentImage returns the currently used image version of the cluster.
|
||||||
@ -327,7 +327,7 @@ func (u *Upgrader) UpdateAttestationConfig(ctx context.Context, newAttestConfig
|
|||||||
}
|
}
|
||||||
joinConfig.Data[constants.AttestationConfigFilename] = string(newConfigJSON)
|
joinConfig.Data[constants.AttestationConfigFilename] = string(newConfigJSON)
|
||||||
u.log.Debugf("Triggering attestation config update now")
|
u.log.Debugf("Triggering attestation config update now")
|
||||||
if _, err = u.stableInterface.updateConfigMap(ctx, joinConfig); err != nil {
|
if _, err = u.stableInterface.UpdateConfigMap(ctx, joinConfig); err != nil {
|
||||||
return fmt.Errorf("setting new attestation config: %w", err)
|
return fmt.Errorf("setting new attestation config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +338,7 @@ func (u *Upgrader) UpdateAttestationConfig(ctx context.Context, newAttestConfig
|
|||||||
// GetClusterAttestationConfig fetches the join-config configmap from the cluster, extracts the config
|
// GetClusterAttestationConfig fetches the join-config configmap from the cluster, extracts the config
|
||||||
// and returns both the full configmap and the attestation config.
|
// and returns both the full configmap and the attestation config.
|
||||||
func (u *Upgrader) GetClusterAttestationConfig(ctx context.Context, variant variant.Variant) (config.AttestationCfg, *corev1.ConfigMap, error) {
|
func (u *Upgrader) GetClusterAttestationConfig(ctx context.Context, variant variant.Variant) (config.AttestationCfg, *corev1.ConfigMap, error) {
|
||||||
existingConf, err := u.stableInterface.getCurrentConfigMap(ctx, constants.JoinConfigMap)
|
existingConf, err := u.stableInterface.GetCurrentConfigMap(ctx, constants.JoinConfigMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("retrieving current attestation config: %w", err)
|
return nil, nil, fmt.Errorf("retrieving current attestation config: %w", err)
|
||||||
}
|
}
|
||||||
@ -361,7 +361,7 @@ func (u *Upgrader) GetClusterAttestationConfig(ctx context.Context, variant vari
|
|||||||
|
|
||||||
// applyComponentsCM applies the k8s components ConfigMap to the cluster.
|
// applyComponentsCM applies the k8s components ConfigMap to the cluster.
|
||||||
func (u *Upgrader) applyComponentsCM(ctx context.Context, components *corev1.ConfigMap) error {
|
func (u *Upgrader) applyComponentsCM(ctx context.Context, components *corev1.ConfigMap) error {
|
||||||
_, err := u.stableInterface.createConfigMap(ctx, components)
|
_, err := u.stableInterface.CreateConfigMap(ctx, components)
|
||||||
// If the map already exists we can use that map and assume it has the same content as 'configMap'.
|
// If the map already exists we can use that map and assume it has the same content as 'configMap'.
|
||||||
if err != nil && !k8serrors.IsAlreadyExists(err) {
|
if err != nil && !k8serrors.IsAlreadyExists(err) {
|
||||||
return fmt.Errorf("creating k8s-components ConfigMap: %w. %T", err, err)
|
return fmt.Errorf("creating k8s-components ConfigMap: %w. %T", err, err)
|
||||||
@ -486,32 +486,40 @@ func upgradeInProgress(nodeVersion updatev1alpha1.NodeVersion) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type stableInterface interface {
|
// StableInterface is an interface to interact with stable resources.
|
||||||
getCurrentConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error)
|
type StableInterface interface {
|
||||||
updateConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error)
|
GetCurrentConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error)
|
||||||
createConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error)
|
UpdateConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error)
|
||||||
kubernetesVersion() (string, error)
|
CreateConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error)
|
||||||
|
KubernetesVersion() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStableClient returns a new StableInterface.
|
||||||
|
func NewStableClient(client kubernetes.Interface) StableInterface {
|
||||||
|
return &stableClient{client: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
type stableClient struct {
|
type stableClient struct {
|
||||||
client kubernetes.Interface
|
client kubernetes.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCurrent returns a ConfigMap given it's name.
|
// GetCurrentConfigMap returns a ConfigMap given it's name.
|
||||||
func (u *stableClient) getCurrentConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error) {
|
func (u *stableClient) GetCurrentConfigMap(ctx context.Context, name string) (*corev1.ConfigMap, error) {
|
||||||
return u.client.CoreV1().ConfigMaps(constants.ConstellationNamespace).Get(ctx, name, metav1.GetOptions{})
|
return u.client.CoreV1().ConfigMaps(constants.ConstellationNamespace).Get(ctx, name, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// update updates the given ConfigMap.
|
// UpdateConfigMap updates the given ConfigMap.
|
||||||
func (u *stableClient) updateConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) {
|
func (u *stableClient) UpdateConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) {
|
||||||
return u.client.CoreV1().ConfigMaps(constants.ConstellationNamespace).Update(ctx, configMap, metav1.UpdateOptions{})
|
return u.client.CoreV1().ConfigMaps(constants.ConstellationNamespace).Update(ctx, configMap, metav1.UpdateOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *stableClient) createConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) {
|
// CreateConfigMap creates the given ConfigMap.
|
||||||
|
func (u *stableClient) CreateConfigMap(ctx context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) {
|
||||||
return u.client.CoreV1().ConfigMaps(constants.ConstellationNamespace).Create(ctx, configMap, metav1.CreateOptions{})
|
return u.client.CoreV1().ConfigMaps(constants.ConstellationNamespace).Create(ctx, configMap, metav1.CreateOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *stableClient) kubernetesVersion() (string, error) {
|
// KubernetesVersion returns the Kubernetes version of the cluster.
|
||||||
|
func (u *stableClient) KubernetesVersion() (string, error) {
|
||||||
serverVersion, err := u.client.Discovery().ServerVersion()
|
serverVersion, err := u.client.Discovery().ServerVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -580,11 +580,11 @@ type stubStableClient struct {
|
|||||||
k8sErr error
|
k8sErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubStableClient) getCurrentConfigMap(_ context.Context, name string) (*corev1.ConfigMap, error) {
|
func (s *stubStableClient) GetCurrentConfigMap(_ context.Context, name string) (*corev1.ConfigMap, error) {
|
||||||
return s.configMaps[name], s.getErr
|
return s.configMaps[name], s.getErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubStableClient) updateConfigMap(_ context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) {
|
func (s *stubStableClient) UpdateConfigMap(_ context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) {
|
||||||
if s.updatedConfigMaps == nil {
|
if s.updatedConfigMaps == nil {
|
||||||
s.updatedConfigMaps = map[string]*corev1.ConfigMap{}
|
s.updatedConfigMaps = map[string]*corev1.ConfigMap{}
|
||||||
}
|
}
|
||||||
@ -592,7 +592,7 @@ func (s *stubStableClient) updateConfigMap(_ context.Context, configMap *corev1.
|
|||||||
return s.updatedConfigMaps[configMap.ObjectMeta.Name], s.updateErr
|
return s.updatedConfigMaps[configMap.ObjectMeta.Name], s.updateErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubStableClient) createConfigMap(_ context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) {
|
func (s *stubStableClient) CreateConfigMap(_ context.Context, configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) {
|
||||||
if s.configMaps == nil {
|
if s.configMaps == nil {
|
||||||
s.configMaps = map[string]*corev1.ConfigMap{}
|
s.configMaps = map[string]*corev1.ConfigMap{}
|
||||||
}
|
}
|
||||||
@ -600,7 +600,7 @@ func (s *stubStableClient) createConfigMap(_ context.Context, configMap *corev1.
|
|||||||
return s.configMaps[configMap.ObjectMeta.Name], s.createErr
|
return s.configMaps[configMap.ObjectMeta.Name], s.createErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubStableClient) kubernetesVersion() (string, error) {
|
func (s *stubStableClient) KubernetesVersion() (string, error) {
|
||||||
return s.k8sVersion, s.k8sErr
|
return s.k8sVersion, s.k8sErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,7 +600,9 @@ func (c *Config) GetAttestationConfig() AttestationCfg {
|
|||||||
return c.Attestation.AWSNitroTPM
|
return c.Attestation.AWSNitroTPM
|
||||||
}
|
}
|
||||||
if c.Attestation.AzureSEVSNP != nil {
|
if c.Attestation.AzureSEVSNP != nil {
|
||||||
return c.Attestation.AzureSEVSNP
|
cp := *c.Attestation.AzureSEVSNP
|
||||||
|
cp.setWantLatestToFalse()
|
||||||
|
return &cp
|
||||||
}
|
}
|
||||||
if c.Attestation.AzureTrustedLaunch != nil {
|
if c.Attestation.AzureTrustedLaunch != nil {
|
||||||
return c.Attestation.AzureTrustedLaunch
|
return c.Attestation.AzureTrustedLaunch
|
||||||
@ -1043,6 +1045,14 @@ type AzureSEVSNP struct {
|
|||||||
AMDRootKey Certificate `json:"amdRootKey" yaml:"amdRootKey"`
|
AMDRootKey Certificate `json:"amdRootKey" yaml:"amdRootKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setWantLatestToFalse sets the WantLatest field to false for all versions in order to unmarshal the numerical versions instead of the string "latest".
|
||||||
|
func (c *AzureSEVSNP) setWantLatestToFalse() {
|
||||||
|
c.BootloaderVersion.WantLatest = false
|
||||||
|
c.TEEVersion.WantLatest = false
|
||||||
|
c.SNPVersion.WantLatest = false
|
||||||
|
c.MicrocodeVersion.WantLatest = false
|
||||||
|
}
|
||||||
|
|
||||||
// AzureTrustedLaunch is the configuration for Azure Trusted Launch attestation.
|
// AzureTrustedLaunch is the configuration for Azure Trusted Launch attestation.
|
||||||
type AzureTrustedLaunch struct {
|
type AzureTrustedLaunch struct {
|
||||||
// description: |
|
// description: |
|
||||||
|
@ -42,7 +42,7 @@ func TestDefaultConfig(t *testing.T) {
|
|||||||
assert.NotNil(def)
|
assert.NotNil(def)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultConfigWritesLatestVersion(t *testing.T) {
|
func TestDefaultConfigMarshalsLatestVersion(t *testing.T) {
|
||||||
conf := Default()
|
conf := Default()
|
||||||
bt, err := yaml.Marshal(conf)
|
bt, err := yaml.Marshal(conf)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
@ -57,6 +57,24 @@ func TestDefaultConfigWritesLatestVersion(t *testing.T) {
|
|||||||
assert.Equal("latest", mp.getAzureSEVSNPVersion("bootloaderVersion"))
|
assert.Equal("latest", mp.getAzureSEVSNPVersion("bootloaderVersion"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetAttestationConfigMarshalsNumericalVersion(t *testing.T) {
|
||||||
|
conf := Default()
|
||||||
|
conf.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
|
||||||
|
|
||||||
|
attestationCfg := conf.GetAttestationConfig()
|
||||||
|
bt, err := yaml.Marshal(attestationCfg)
|
||||||
|
require := require.New(t)
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
var mp map[string]interface{}
|
||||||
|
require.NoError(yaml.Unmarshal(bt, &mp))
|
||||||
|
assert := assert.New(t)
|
||||||
|
assert.Equal(placeholderVersionValue, mp["microcodeVersion"])
|
||||||
|
assert.Equal(placeholderVersionValue, mp["teeVersion"])
|
||||||
|
assert.Equal(placeholderVersionValue, mp["snpVersion"])
|
||||||
|
assert.Equal(placeholderVersionValue, mp["bootloaderVersion"])
|
||||||
|
}
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
config configMap
|
config configMap
|
||||||
|
Loading…
x
Reference in New Issue
Block a user