mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-12-16 16:34:09 -05:00
parse init inputs
This commit is contained in:
parent
e6f4be73bb
commit
d36821ef0b
5 changed files with 173 additions and 12 deletions
|
|
@ -570,16 +570,23 @@ func (h *HexBytes) UnmarshalYAML(unmarshal func(any) error) error {
|
||||||
}
|
}
|
||||||
hexString = hex.EncodeToString(oldHexBytes)
|
hexString = hex.EncodeToString(oldHexBytes)
|
||||||
}
|
}
|
||||||
|
s, err := UnmarshalHexBytes(hexString)
|
||||||
bytes, err := hex.DecodeString(hexString)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("decoding hex bytes: %w", err)
|
return fmt.Errorf("unmarshalling hex bytes: %w", err)
|
||||||
}
|
}
|
||||||
|
*h = s
|
||||||
*h = bytes
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalHexBytes unmarshals a hex-encoded string into the byte slice.
|
||||||
|
func UnmarshalHexBytes(hexEncoded string) (HexBytes, error) {
|
||||||
|
bytes, err := hex.DecodeString(hexEncoded)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decoding hex bytes: %w", err)
|
||||||
|
}
|
||||||
|
return HexBytes(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalYAML implements the yaml.Marshaler interface.
|
// MarshalYAML implements the yaml.Marshaler interface.
|
||||||
func (h HexBytes) MarshalYAML() (any, error) {
|
func (h HexBytes) MarshalYAML() (any, error) {
|
||||||
return hex.EncodeToString(h), nil
|
return hex.EncodeToString(h), nil
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ resource "constellation_cluster" "foo" {
|
||||||
kubernetes_version = "v1.27.6"
|
kubernetes_version = "v1.27.6"
|
||||||
debug = false
|
debug = false
|
||||||
init_endpoint = "10.10.10.10" # should use public ip of LB resource, ideally also provisioned through TF
|
init_endpoint = "10.10.10.10" # should use public ip of LB resource, ideally also provisioned through TF
|
||||||
|
api_server_cert_sans = ["10.10.10.10"] # should use output from infra module
|
||||||
kubernetes_api_endpoint = "10.10.10.10" # should use public ip of LB resource, ideally also provisioned through TF
|
kubernetes_api_endpoint = "10.10.10.10" # should use public ip of LB resource, ideally also provisioned through TF
|
||||||
constellation_microservice_version = "v2.13.0" # optional value, set to provider version by default.
|
constellation_microservice_version = "v2.13.0" # optional value, set to provider version by default.
|
||||||
extra_microservices = {
|
extra_microservices = {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ require (
|
||||||
cloud.google.com/go/compute v1.23.0 // indirect
|
cloud.google.com/go/compute v1.23.0 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||||
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect
|
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect
|
||||||
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,17 @@ package provider
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/constellation"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/grpc/dialer"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/state"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
|
|
@ -43,6 +51,7 @@ type ClusterResourceModel struct {
|
||||||
KubernetesVersion types.String `tfsdk:"kubernetes_version"`
|
KubernetesVersion types.String `tfsdk:"kubernetes_version"`
|
||||||
Debug types.Bool `tfsdk:"debug"`
|
Debug types.Bool `tfsdk:"debug"`
|
||||||
InitEndpoint types.String `tfsdk:"init_endpoint"`
|
InitEndpoint types.String `tfsdk:"init_endpoint"`
|
||||||
|
APIServerCertSANs types.List `tfsdk:"api_server_cert_sans"`
|
||||||
KubernetesAPIEndpoint types.String `tfsdk:"kubernetes_api_endpoint"`
|
KubernetesAPIEndpoint types.String `tfsdk:"kubernetes_api_endpoint"`
|
||||||
MicroserviceVersion types.String `tfsdk:"constellation_microservices_version"`
|
MicroserviceVersion types.String `tfsdk:"constellation_microservices_version"`
|
||||||
ExtraMicroservices types.Object `tfsdk:"extra_microservices"`
|
ExtraMicroservices types.Object `tfsdk:"extra_microservices"`
|
||||||
|
|
@ -52,7 +61,7 @@ type ClusterResourceModel struct {
|
||||||
OwnerID types.String `tfsdk:"owner_id"`
|
OwnerID types.String `tfsdk:"owner_id"`
|
||||||
ClusterID types.String `tfsdk:"cluster_id"`
|
ClusterID types.String `tfsdk:"cluster_id"`
|
||||||
Kubeconfig types.String `tfsdk:"kubeconfig"`
|
Kubeconfig types.String `tfsdk:"kubeconfig"`
|
||||||
// NetworkConfig types.Object `tfsdk:"network_config"` // TODO(elchead): do when clear what is needed
|
NetworkConfig types.Object `tfsdk:"network_config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata returns the metadata of the resource.
|
// Metadata returns the metadata of the resource.
|
||||||
|
|
@ -119,14 +128,42 @@ func (r *ClusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"api_server_cert_sans": schema.ListAttribute{
|
||||||
|
MarkdownDescription: "The additional certificate SANs to use for the API server.",
|
||||||
|
Description: "The additional certificate SANs to use for the API server.",
|
||||||
|
ElementType: types.StringType,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"network_config": schema.SingleNestedAttribute{
|
||||||
|
MarkdownDescription: "Network config settings.",
|
||||||
|
Description: "Network config settings.",
|
||||||
|
Required: true,
|
||||||
|
Attributes: map[string]schema.Attribute{
|
||||||
|
"ip_cidr_node": schema.StringAttribute{
|
||||||
|
Required: true,
|
||||||
|
MarkdownDescription: "The CIDR to use for the node network.",
|
||||||
|
Description: "The CIDR to use for the node network.",
|
||||||
|
},
|
||||||
|
"service_cidr": schema.StringAttribute{
|
||||||
|
Required: true,
|
||||||
|
MarkdownDescription: "The CIDR to use for the service network.",
|
||||||
|
Description: "The CIDR to use for the service network.",
|
||||||
|
},
|
||||||
|
"in_cluster_endpoint": schema.StringAttribute{
|
||||||
|
Required: true,
|
||||||
|
MarkdownDescription: "The endpoint to use for the in-cluster communication.",
|
||||||
|
Description: "The endpoint to use for the in-cluster communication.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"master_secret": schema.StringAttribute{
|
"master_secret": schema.StringAttribute{
|
||||||
MarkdownDescription: "The master secret to use for the cluster.",
|
MarkdownDescription: "The master secret to use for the cluster.",
|
||||||
Description: "The master secret to use for the cluster.",
|
Description: "The master secret to use for the cluster.",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"init_secret": schema.StringAttribute{
|
"init_secret": schema.StringAttribute{
|
||||||
MarkdownDescription: "The init secret to use for the cluster.",
|
MarkdownDescription: "The hex-encoded init secret to use for the cluster.",
|
||||||
Description: "The init secret to use for the cluster.",
|
Description: "The hex-encoded init secret to use for the cluster.",
|
||||||
Required: true,
|
Required: true,
|
||||||
}, // TODO merge / derive from master secret?
|
}, // TODO merge / derive from master secret?
|
||||||
"attestation": newAttestationConfigAttribute(true),
|
"attestation": newAttestationConfigAttribute(true),
|
||||||
|
|
@ -209,12 +246,102 @@ func (r *ClusterResource) Create(ctx context.Context, req resource.CreateRequest
|
||||||
data.OwnerID = types.StringValue("owner_id")
|
data.OwnerID = types.StringValue("owner_id")
|
||||||
data.ClusterID = types.StringValue("cluster_id")
|
data.ClusterID = types.StringValue("cluster_id")
|
||||||
data.Kubeconfig = types.StringValue("kubeconfig")
|
data.Kubeconfig = types.StringValue("kubeconfig")
|
||||||
// applier := constellation.NewApplier(log)
|
|
||||||
_, err = choose.Validator(attestationCfg, &tfLogger{dg: &resp.Diagnostics})
|
// run init RPC
|
||||||
|
log := &tfLogger{dg: &resp.Diagnostics}
|
||||||
|
newDialer := func(validator atls.Validator) *dialer.Dialer {
|
||||||
|
return dialer.New(nil, validator, &net.Dialer{})
|
||||||
|
}
|
||||||
|
applier := constellation.NewApplier(log, &nopSpinner{}, newDialer)
|
||||||
|
validator, err := choose.Validator(attestationCfg, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Diagnostics.AddError("Choosing validator", err.Error())
|
resp.Diagnostics.AddError("Choosing validator", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
masterSecret, err := applier.GenerateMasterSecret()
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError("Generating master secret", err.Error())
|
||||||
|
}
|
||||||
|
measurementSalt, err := applier.GenerateMeasurementSalt()
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError("Generating measurement salt", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
initSecret, err := state.UnmarshalHexBytes(data.InitSecret.ValueString())
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError("Unmarshalling init secret. Needs to be hex encoded.", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apiServerCertSANs := make([]string, 0, len(data.APIServerCertSANs.Elements()))
|
||||||
|
for _, san := range data.APIServerCertSANs.Elements() {
|
||||||
|
apiServerCertSANs = append(apiServerCertSANs, san.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var networkCfg networkConfig
|
||||||
|
diags = data.NetworkConfig.As(ctx, &networkCfg, basetypes.ObjectAsOptions{})
|
||||||
|
resp.Diagnostics.Append(diags...)
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
infra := state.Infrastructure{
|
||||||
|
UID: data.UID.ValueString(),
|
||||||
|
ClusterEndpoint: data.KubernetesAPIEndpoint.ValueString(),
|
||||||
|
InClusterEndpoint: networkCfg.InClusterEndpoint, // TODO(elchead): optional or not?; otherwise default to ClusterEndpoint?
|
||||||
|
InitSecret: initSecret,
|
||||||
|
APIServerCertSANs: apiServerCertSANs,
|
||||||
|
Name: data.Name.ValueString(),
|
||||||
|
IPCidrNode: networkCfg.IPCIDRNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
state := state.New().SetInfrastructure(infra)
|
||||||
|
var k8sVersion versions.ValidK8sVersion
|
||||||
|
if data.KubernetesVersion.ValueString() != "" {
|
||||||
|
k8sVersion, err = versions.NewValidK8sVersion(data.KubernetesVersion.ValueString(), true)
|
||||||
|
if err != nil {
|
||||||
|
resp.Diagnostics.AddError("Parsing Kubernetes version", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
k8sVersion = config.Default().KubernetesVersion
|
||||||
|
resp.Diagnostics.AddWarning("Using default Kubernetes version", string(k8sVersion))
|
||||||
|
}
|
||||||
|
fmt.Println(state, validator, measurementSalt, masterSecret, k8sVersion)
|
||||||
|
//clusterLogs := &bytes.Buffer{} // write to tflog?
|
||||||
|
//initResp, err := applier.Init(
|
||||||
|
// ctx, validator, state, clusterLogs,
|
||||||
|
// constellation.InitPayload{
|
||||||
|
// MasterSecret: masterSecret,
|
||||||
|
// MeasurementSalt: measurementSalt,
|
||||||
|
// K8sVersion: k8sVersion,
|
||||||
|
// ConformanceMode: false, // TODO(elchead): leo?
|
||||||
|
// ServiceCIDR: networkCfg.ServiceCIDR,
|
||||||
|
// })
|
||||||
|
//if err != nil {
|
||||||
|
// if err != nil {
|
||||||
|
// var nonRetriable *constellation.NonRetriableInitError
|
||||||
|
// if errors.As(err, &nonRetriable) {
|
||||||
|
// resp.Diagnostics.AddError("Cluster initialization failed.", fmt.Sprintf("This error is not recoverable. Cleanup resources and try again. Error: %s", err.Error()))
|
||||||
|
// //if nonRetriable.LogCollectionErr != nil { // TODO how to store logs from clusterLogs?
|
||||||
|
// // resp.Diagnostics.AddWarning("Bootstrapper log collection fialed.", fmt.Sprintf("Failed to collect logs from bootstrapper: %s\n", nonRetriable.LogCollectionErr))
|
||||||
|
// //} else {
|
||||||
|
// // cmd.PrintErrf("Fetched bootstrapper logs are stored in %q\n", a.flags.pathPrefixer.PrefixPrintablePath(constants.ErrorLog))
|
||||||
|
// //}
|
||||||
|
// } else {
|
||||||
|
// resp.Diagnostics.AddError("Cluster initialization failed.", fmt.Sprintf("You might try to apply the resource again. Error: %s", err.Error()))
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// resp.Diagnostics.AddError("Running init RPC", err.Error())
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
|
//k8sLogs := &bytes.Buffer{} // write to tflog?
|
||||||
|
//kubeUpgrader, err := kubecmd.New(k8sLogs, initResp.Kubeconfig, file.NewHandler(afero.NewMemMapFs()), log) // fileHandler should not be needed since no backups are supported.. maybe defer Backup Impl to wrapped struct for CLI?
|
||||||
|
//if err != nil {
|
||||||
|
// resp.Diagnostics.AddError("Creating kube upgrader", err.Error())
|
||||||
|
//}
|
||||||
|
// fmt.Println(initResp)
|
||||||
|
|
||||||
// Write logs using the tflog package
|
// Write logs using the tflog package
|
||||||
// Documentation: https://terraform.io/plugin/log
|
// Documentation: https://terraform.io/plugin/log
|
||||||
|
|
@ -299,6 +426,10 @@ type tfLogger struct {
|
||||||
dg *diag.Diagnostics
|
dg *diag.Diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *tfLogger) Debugf(format string, args ...any) {
|
||||||
|
tflog.Debug(context.Background(), fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
func (l *tfLogger) Infof(format string, args ...any) {
|
func (l *tfLogger) Infof(format string, args ...any) {
|
||||||
tflog.Info(context.Background(), fmt.Sprintf(format, args...))
|
tflog.Info(context.Background(), fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|
@ -306,3 +437,19 @@ func (l *tfLogger) Infof(format string, args ...any) {
|
||||||
func (l *tfLogger) Warnf(format string, args ...any) {
|
func (l *tfLogger) Warnf(format string, args ...any) {
|
||||||
l.dg.AddWarning(fmt.Sprintf(format, args...), "")
|
l.dg.AddWarning(fmt.Sprintf(format, args...), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nopSpinner struct {
|
||||||
|
io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *nopSpinner) Start(string, bool) {}
|
||||||
|
func (s *nopSpinner) Stop() {}
|
||||||
|
func (s *nopSpinner) Write(_ []byte) (n int, err error) {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type networkConfig struct {
|
||||||
|
IPCIDRNode string `tfsdk:"ip_cidr_node"`
|
||||||
|
ServiceCIDR string `tfsdk:"service_cidr"`
|
||||||
|
InClusterEndpoint string `tfsdk:"in_cluster_endpoint"`
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,17 @@ func TestAccClusterResource(t *testing.T) {
|
||||||
|
|
||||||
resource "constellation_cluster" "test" {
|
resource "constellation_cluster" "test" {
|
||||||
uid = "test"
|
uid = "test"
|
||||||
master_secret = "secret"
|
master_secret = "48656c6c6f"
|
||||||
init_secret = "secret"
|
init_secret = "48656c6c6f"
|
||||||
attestation = data.constellation_attestation.att.attestation
|
attestation = data.constellation_attestation.att.attestation
|
||||||
extra_microservices = {
|
extra_microservices = {
|
||||||
csi_driver = true
|
csi_driver = true
|
||||||
}
|
}
|
||||||
|
network_config = {
|
||||||
|
ip_cidr_node = "10.10.10.0/16"
|
||||||
|
service_cidr = "10.10.10.0/24"
|
||||||
|
in_cluster_endpoint = "10.10.10.10"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue