mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
AB#2436: Initial support for create/terminate AWS NitroTPM instances
* Add .DS_Store to .gitignore * Add AWS to config / supported instance types * Move AWS terraform skeleton to cli/internal/terraform * Move currently unused IAM to hack/terraform/aws * Print supported AWS instance types when AWS dev flag is set * Block everything aTLS related (e.g. init, verify) until AWS attestation is available * Create/Terminate AWS dev cluster when dev flag is set * Restrict Nitro instances to NitroTPM supported specifically * Pin zone for subnets This is not great for HA, but for now we need to avoid the two subnets ending up in different zones, causing the load balancer to not be able to connect to the targets. Should be replaced later with a better implementation that just uses multiple subnets within the same region dynamically based on # of nodes or similar. * Add AWS/GCP to Terraform TestLoader unit test * Add uid tag and create log group Co-authored-by: Daniel Weiße <dw@edgeless.systems> Co-authored-by: Malte Poll <mp@edgeless.systems>
This commit is contained in:
parent
07f02a442c
commit
04c4cff9f6
3
.gitignore
vendored
3
.gitignore
vendored
@ -43,3 +43,6 @@ image/config.mk
|
|||||||
.terraform.lock.hcl
|
.terraform.lock.hcl
|
||||||
.terraform.tfstate.lock.info
|
.terraform.tfstate.lock.info
|
||||||
*.tfvars
|
*.tfvars
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
@ -46,6 +46,17 @@ func NewCreator(out io.Writer) *Creator {
|
|||||||
func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, config *config.Config, name, insType string, controlPlaneCount, workerCount int,
|
func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, config *config.Config, name, insType string, controlPlaneCount, workerCount int,
|
||||||
) (clusterid.File, error) {
|
) (clusterid.File, error) {
|
||||||
switch provider {
|
switch provider {
|
||||||
|
case cloudprovider.AWS:
|
||||||
|
// TODO: Remove this once AWS is supported.
|
||||||
|
if os.Getenv("CONSTELLATION_AWS_DEV") != "1" {
|
||||||
|
return clusterid.File{}, fmt.Errorf("AWS isn't supported yet")
|
||||||
|
}
|
||||||
|
cl, err := c.newTerraformClient(ctx, provider)
|
||||||
|
if err != nil {
|
||||||
|
return clusterid.File{}, err
|
||||||
|
}
|
||||||
|
defer cl.RemoveInstaller()
|
||||||
|
return c.createAWS(ctx, cl, config, name, insType, controlPlaneCount, workerCount)
|
||||||
case cloudprovider.GCP:
|
case cloudprovider.GCP:
|
||||||
cl, err := c.newTerraformClient(ctx, provider)
|
cl, err := c.newTerraformClient(ctx, provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -76,6 +87,38 @@ func (c *Creator) Create(ctx context.Context, provider cloudprovider.Provider, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Creator) createAWS(ctx context.Context, cl terraformClient, config *config.Config,
|
||||||
|
name, insType string, controlPlaneCount, workerCount int,
|
||||||
|
) (idFile clusterid.File, retErr error) {
|
||||||
|
defer rollbackOnError(context.Background(), c.out, &retErr, &rollbackerTerraform{client: cl})
|
||||||
|
|
||||||
|
vars := &terraform.AWSVariables{
|
||||||
|
CommonVariables: terraform.CommonVariables{
|
||||||
|
Name: name,
|
||||||
|
CountControlPlanes: controlPlaneCount,
|
||||||
|
CountWorkers: workerCount,
|
||||||
|
StateDiskSizeGB: config.StateDiskSizeGB,
|
||||||
|
},
|
||||||
|
Region: config.Provider.AWS.Region,
|
||||||
|
Zone: config.Provider.AWS.Zone,
|
||||||
|
InstanceType: insType,
|
||||||
|
AMIImageID: config.Provider.AWS.Image,
|
||||||
|
IAMProfileControlPlane: config.Provider.AWS.IAMProfileControlPlane,
|
||||||
|
IAMProfileWorkerNodes: config.Provider.AWS.IAMProfileWorkerNodes,
|
||||||
|
Debug: config.IsDebugCluster(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ip, err := cl.CreateCluster(ctx, name, vars)
|
||||||
|
if err != nil {
|
||||||
|
return clusterid.File{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return clusterid.File{
|
||||||
|
CloudProvider: cloudprovider.AWS,
|
||||||
|
IP: ip,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Creator) createGCP(ctx context.Context, cl terraformClient, config *config.Config,
|
func (c *Creator) createGCP(ctx context.Context, cl terraformClient, config *config.Config,
|
||||||
name, insType string, controlPlaneCount, workerCount int,
|
name, insType string, controlPlaneCount, workerCount int,
|
||||||
) (idFile clusterid.File, retErr error) {
|
) (idFile clusterid.File, retErr error) {
|
||||||
|
@ -36,6 +36,10 @@ type Validator struct {
|
|||||||
|
|
||||||
func NewValidator(provider cloudprovider.Provider, config *config.Config) (*Validator, error) {
|
func NewValidator(provider cloudprovider.Provider, config *config.Config) (*Validator, error) {
|
||||||
v := Validator{}
|
v := Validator{}
|
||||||
|
if provider == cloudprovider.AWS {
|
||||||
|
// TODO: Implement AWS validator
|
||||||
|
return nil, errors.New("no validator for AWS available yet")
|
||||||
|
}
|
||||||
if provider == cloudprovider.Unknown {
|
if provider == cloudprovider.Unknown {
|
||||||
return nil, errors.New("unknown cloud provider")
|
return nil, errors.New("unknown cloud provider")
|
||||||
}
|
}
|
||||||
@ -100,14 +104,14 @@ func (v *Validator) updatePCR(pcrIndex uint32, encoded string) error {
|
|||||||
|
|
||||||
func (v *Validator) setPCRs(config *config.Config) error {
|
func (v *Validator) setPCRs(config *config.Config) error {
|
||||||
switch v.provider {
|
switch v.provider {
|
||||||
case cloudprovider.GCP:
|
case cloudprovider.AWS:
|
||||||
gcpPCRs := config.Provider.GCP.Measurements
|
awsPCRs := config.Provider.AWS.Measurements
|
||||||
enforcedPCRs := config.Provider.GCP.EnforcedMeasurements
|
enforcedPCRs := config.Provider.AWS.EnforcedMeasurements
|
||||||
if err := v.checkPCRs(gcpPCRs, enforcedPCRs); err != nil {
|
if err := v.checkPCRs(awsPCRs, enforcedPCRs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
v.enforcedPCRs = enforcedPCRs
|
v.enforcedPCRs = enforcedPCRs
|
||||||
v.pcrs = gcpPCRs
|
v.pcrs = awsPCRs
|
||||||
case cloudprovider.Azure:
|
case cloudprovider.Azure:
|
||||||
azurePCRs := config.Provider.Azure.Measurements
|
azurePCRs := config.Provider.Azure.Measurements
|
||||||
enforcedPCRs := config.Provider.Azure.EnforcedMeasurements
|
enforcedPCRs := config.Provider.Azure.EnforcedMeasurements
|
||||||
@ -116,6 +120,14 @@ func (v *Validator) setPCRs(config *config.Config) error {
|
|||||||
}
|
}
|
||||||
v.enforcedPCRs = enforcedPCRs
|
v.enforcedPCRs = enforcedPCRs
|
||||||
v.pcrs = azurePCRs
|
v.pcrs = azurePCRs
|
||||||
|
case cloudprovider.GCP:
|
||||||
|
gcpPCRs := config.Provider.GCP.Measurements
|
||||||
|
enforcedPCRs := config.Provider.GCP.EnforcedMeasurements
|
||||||
|
if err := v.checkPCRs(gcpPCRs, enforcedPCRs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.enforcedPCRs = enforcedPCRs
|
||||||
|
v.pcrs = gcpPCRs
|
||||||
case cloudprovider.QEMU:
|
case cloudprovider.QEMU:
|
||||||
qemuPCRs := config.Provider.QEMU.Measurements
|
qemuPCRs := config.Provider.QEMU.Measurements
|
||||||
enforcedPCRs := config.Provider.QEMU.EnforcedMeasurements
|
enforcedPCRs := config.Provider.QEMU.EnforcedMeasurements
|
||||||
|
@ -20,7 +20,7 @@ func NewConfigCmd() *cobra.Command {
|
|||||||
|
|
||||||
cmd.AddCommand(newConfigGenerateCmd())
|
cmd.AddCommand(newConfigGenerateCmd())
|
||||||
cmd.AddCommand(newConfigFetchMeasurementsCmd())
|
cmd.AddCommand(newConfigFetchMeasurementsCmd())
|
||||||
cmd.AddCommand(NewConfigInstanceTypesCmd())
|
cmd.AddCommand(newConfigInstanceTypesCmd())
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,14 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewConfigInstanceTypesCmd() *cobra.Command {
|
func newConfigInstanceTypesCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "instance-types",
|
Use: "instance-types",
|
||||||
Short: "Print the supported instance types for all cloud providers",
|
Short: "Print the supported instance types for all cloud providers",
|
||||||
@ -26,7 +27,16 @@ func NewConfigInstanceTypesCmd() *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Merge everything back into one function once AWS is supported.
|
||||||
func printSupportedInstanceTypes(cmd *cobra.Command, args []string) {
|
func printSupportedInstanceTypes(cmd *cobra.Command, args []string) {
|
||||||
|
if os.Getenv("CONSTELLATION_AWS_DEV") == "1" {
|
||||||
|
printSupportedInstanceTypesWithAWS()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printSupportedInstanceTypesWithoutAWS()
|
||||||
|
}
|
||||||
|
|
||||||
|
func printSupportedInstanceTypesWithoutAWS() {
|
||||||
fmt.Printf(`Azure Confidential VM instance types:
|
fmt.Printf(`Azure Confidential VM instance types:
|
||||||
%v
|
%v
|
||||||
Azure Trusted Launch instance types:
|
Azure Trusted Launch instance types:
|
||||||
@ -36,6 +46,18 @@ GCP instance types:
|
|||||||
`, formatInstanceTypes(instancetypes.AzureCVMInstanceTypes), formatInstanceTypes(instancetypes.AzureTrustedLaunchInstanceTypes), formatInstanceTypes(instancetypes.GCPInstanceTypes))
|
`, formatInstanceTypes(instancetypes.AzureCVMInstanceTypes), formatInstanceTypes(instancetypes.AzureTrustedLaunchInstanceTypes), formatInstanceTypes(instancetypes.GCPInstanceTypes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printSupportedInstanceTypesWithAWS() {
|
||||||
|
fmt.Printf(`AWS instance families:
|
||||||
|
%v
|
||||||
|
Azure Confidential VM instance types:
|
||||||
|
%v
|
||||||
|
Azure Trusted Launch instance types:
|
||||||
|
%v
|
||||||
|
GCP instance types:
|
||||||
|
%v
|
||||||
|
`, formatInstanceTypes(instancetypes.AWSSupportedInstanceFamilies), formatInstanceTypes(instancetypes.AzureCVMInstanceTypes), formatInstanceTypes(instancetypes.AzureTrustedLaunchInstanceTypes), formatInstanceTypes(instancetypes.GCPInstanceTypes))
|
||||||
|
}
|
||||||
|
|
||||||
func formatInstanceTypes(types []string) string {
|
func formatInstanceTypes(types []string) string {
|
||||||
return "\t" + strings.Join(types, "\n\t")
|
return "\t" + strings.Join(types, "\n\t")
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,8 @@ func create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler,
|
|||||||
provider := config.GetProvider()
|
provider := config.GetProvider()
|
||||||
var instanceType string
|
var instanceType string
|
||||||
switch provider {
|
switch provider {
|
||||||
|
case cloudprovider.AWS:
|
||||||
|
instanceType = config.Provider.AWS.InstanceType
|
||||||
case cloudprovider.Azure:
|
case cloudprovider.Azure:
|
||||||
instanceType = config.Provider.Azure.InstanceType
|
instanceType = config.Provider.Azure.InstanceType
|
||||||
case cloudprovider.GCP:
|
case cloudprovider.GCP:
|
||||||
|
@ -9,6 +9,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -17,8 +18,8 @@ import (
|
|||||||
// warnAWS warns that AWS isn't supported.
|
// warnAWS warns that AWS isn't supported.
|
||||||
func warnAWS(providerPos int) cobra.PositionalArgs {
|
func warnAWS(providerPos int) cobra.PositionalArgs {
|
||||||
return func(cmd *cobra.Command, args []string) error {
|
return func(cmd *cobra.Command, args []string) error {
|
||||||
if cloudprovider.FromString(args[providerPos]) == cloudprovider.AWS {
|
if cloudprovider.FromString(args[providerPos]) == cloudprovider.AWS && os.Getenv("CONSTELLATION_AWS_DEV") != "1" {
|
||||||
return errors.New("AWS isn't supported by this version of Constellation")
|
return errors.New("AWS isn't supported yet")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,24 @@ func TestLoader(t *testing.T) {
|
|||||||
provider cloudprovider.Provider
|
provider cloudprovider.Provider
|
||||||
fileList []string
|
fileList []string
|
||||||
}{
|
}{
|
||||||
|
"aws": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
fileList: []string{
|
||||||
|
"main.tf",
|
||||||
|
"variables.tf",
|
||||||
|
"outputs.tf",
|
||||||
|
"modules",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"gcp": {
|
||||||
|
provider: cloudprovider.GCP,
|
||||||
|
fileList: []string{
|
||||||
|
"main.tf",
|
||||||
|
"variables.tf",
|
||||||
|
"outputs.tf",
|
||||||
|
"modules",
|
||||||
|
},
|
||||||
|
},
|
||||||
"qemu": {
|
"qemu": {
|
||||||
provider: cloudprovider.QEMU,
|
provider: cloudprovider.QEMU,
|
||||||
fileList: []string{
|
fileList: []string{
|
||||||
|
240
cli/internal/terraform/terraform/aws/main.tf
Normal file
240
cli/internal/terraform/terraform/aws/main.tf
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
aws = {
|
||||||
|
source = "hashicorp/aws"
|
||||||
|
version = "~> 4.0"
|
||||||
|
}
|
||||||
|
random = {
|
||||||
|
source = "hashicorp/random"
|
||||||
|
version = "3.4.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Configure the AWS Provider
|
||||||
|
provider "aws" {
|
||||||
|
region = var.region
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
uid = random_id.uid.hex
|
||||||
|
name = "${var.name}-${local.uid}"
|
||||||
|
ports_node_range = "30000-32767"
|
||||||
|
ports_ssh = "22"
|
||||||
|
ports_kubernetes = "6443"
|
||||||
|
ports_bootstrapper = "9000"
|
||||||
|
ports_konnectivity = "8132"
|
||||||
|
ports_verify = "30081"
|
||||||
|
ports_debugd = "4000"
|
||||||
|
|
||||||
|
tags = { constellation-uid = local.uid }
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "random_id" "uid" {
|
||||||
|
byte_length = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_vpc" "vpc" {
|
||||||
|
cidr_block = "192.168.0.0/16"
|
||||||
|
tags = merge(local.tags, { Name = "${local.name}-vpc" })
|
||||||
|
}
|
||||||
|
|
||||||
|
module "public_private_subnet" {
|
||||||
|
source = "./modules/public_private_subnet"
|
||||||
|
name = local.name
|
||||||
|
vpc_id = aws_vpc.vpc.id
|
||||||
|
cidr_vpc_subnet_nodes = "192.168.178.0/24"
|
||||||
|
cidr_vpc_subnet_internet = "192.168.0.0/24"
|
||||||
|
zone = var.zone
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_eip" "lb" {
|
||||||
|
vpc = true
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lb" "front_end" {
|
||||||
|
name = "${local.name}-loadbalancer"
|
||||||
|
internal = false
|
||||||
|
load_balancer_type = "network"
|
||||||
|
tags = local.tags
|
||||||
|
|
||||||
|
subnet_mapping {
|
||||||
|
subnet_id = module.public_private_subnet.public_subnet_id
|
||||||
|
allocation_id = aws_eip.lb.id
|
||||||
|
}
|
||||||
|
enable_cross_zone_load_balancing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "security_group" {
|
||||||
|
name = local.name
|
||||||
|
vpc_id = aws_vpc.vpc.id
|
||||||
|
description = "Security group for ${local.name}"
|
||||||
|
tags = local.tags
|
||||||
|
|
||||||
|
egress {
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
description = "Allow all outbound traffic"
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = split("-", local.ports_node_range)[0]
|
||||||
|
to_port = split("-", local.ports_node_range)[1]
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
description = "K8s node ports"
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: Remove when development is more advanced
|
||||||
|
dynamic "ingress" {
|
||||||
|
for_each = var.debug ? [1] : []
|
||||||
|
content {
|
||||||
|
from_port = local.ports_ssh
|
||||||
|
to_port = local.ports_ssh
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
description = "SSH"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = local.ports_bootstrapper
|
||||||
|
to_port = local.ports_bootstrapper
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
description = "bootstrapper"
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = local.ports_kubernetes
|
||||||
|
to_port = local.ports_kubernetes
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
description = "kubernetes"
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = local.ports_konnectivity
|
||||||
|
to_port = local.ports_konnectivity
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
description = "konnectivity"
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic "ingress" {
|
||||||
|
for_each = var.debug ? [1] : []
|
||||||
|
content {
|
||||||
|
from_port = local.ports_debugd
|
||||||
|
to_port = local.ports_debugd
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
description = "debugd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_log_group" "log_group" {
|
||||||
|
name = local.name
|
||||||
|
retention_in_days = 30
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
module "load_balancer_target_bootstrapper" {
|
||||||
|
source = "./modules/load_balancer_target"
|
||||||
|
name = "${local.name}-bootstrapper"
|
||||||
|
vpc_id = aws_vpc.vpc.id
|
||||||
|
lb_arn = aws_lb.front_end.arn
|
||||||
|
port = local.ports_bootstrapper
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
module "load_balancer_target_kubernetes" {
|
||||||
|
source = "./modules/load_balancer_target"
|
||||||
|
name = "${local.name}-kubernetes"
|
||||||
|
vpc_id = aws_vpc.vpc.id
|
||||||
|
lb_arn = aws_lb.front_end.arn
|
||||||
|
port = local.ports_kubernetes
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
module "load_balancer_target_verify" {
|
||||||
|
source = "./modules/load_balancer_target"
|
||||||
|
name = "${local.name}-verify"
|
||||||
|
vpc_id = aws_vpc.vpc.id
|
||||||
|
lb_arn = aws_lb.front_end.arn
|
||||||
|
port = local.ports_verify
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
module "load_balancer_target_debugd" {
|
||||||
|
count = var.debug ? 1 : 0 // only deploy debugd in debug mode
|
||||||
|
source = "./modules/load_balancer_target"
|
||||||
|
name = "${local.name}-debugd"
|
||||||
|
vpc_id = aws_vpc.vpc.id
|
||||||
|
lb_arn = aws_lb.front_end.arn
|
||||||
|
port = local.ports_debugd
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
module "load_balancer_target_konnectivity" {
|
||||||
|
source = "./modules/load_balancer_target"
|
||||||
|
name = "${local.name}-konnectivity"
|
||||||
|
vpc_id = aws_vpc.vpc.id
|
||||||
|
lb_arn = aws_lb.front_end.arn
|
||||||
|
port = local.ports_konnectivity
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: Remove when development is more advanced
|
||||||
|
module "load_balancer_target_ssh" {
|
||||||
|
count = var.debug ? 1 : 0 // only deploy SSH in debug mode
|
||||||
|
source = "./modules/load_balancer_target"
|
||||||
|
name = "${local.name}-ssh"
|
||||||
|
vpc_id = aws_vpc.vpc.id
|
||||||
|
lb_arn = aws_lb.front_end.arn
|
||||||
|
port = local.ports_ssh
|
||||||
|
tags = local.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
module "instance_group_control_plane" {
|
||||||
|
source = "./modules/instance_group"
|
||||||
|
name = local.name
|
||||||
|
role = "control-plane"
|
||||||
|
uid = local.uid
|
||||||
|
instance_type = var.instance_type
|
||||||
|
instance_count = var.control_plane_count
|
||||||
|
image_id = var.ami
|
||||||
|
state_disk_type = var.state_disk_type
|
||||||
|
state_disk_size = var.state_disk_size
|
||||||
|
target_group_arns = flatten([
|
||||||
|
module.load_balancer_target_bootstrapper.target_group_arn,
|
||||||
|
module.load_balancer_target_kubernetes.target_group_arn,
|
||||||
|
module.load_balancer_target_verify.target_group_arn,
|
||||||
|
module.load_balancer_target_konnectivity.target_group_arn,
|
||||||
|
var.debug ? [module.load_balancer_target_debugd[0].target_group_arn,
|
||||||
|
module.load_balancer_target_ssh[0].target_group_arn] : [],
|
||||||
|
])
|
||||||
|
security_groups = [aws_security_group.security_group.id]
|
||||||
|
subnetwork = module.public_private_subnet.private_subnet_id
|
||||||
|
iam_instance_profile = var.iam_instance_profile_control_plane
|
||||||
|
}
|
||||||
|
|
||||||
|
module "instance_group_worker_nodes" {
|
||||||
|
source = "./modules/instance_group"
|
||||||
|
name = local.name
|
||||||
|
role = "worker"
|
||||||
|
uid = local.uid
|
||||||
|
instance_type = var.instance_type
|
||||||
|
instance_count = var.worker_count
|
||||||
|
image_id = var.ami
|
||||||
|
state_disk_type = var.state_disk_type
|
||||||
|
state_disk_size = var.state_disk_size
|
||||||
|
subnetwork = module.public_private_subnet.private_subnet_id
|
||||||
|
target_group_arns = []
|
||||||
|
security_groups = []
|
||||||
|
iam_instance_profile = var.iam_instance_profile_worker_nodes
|
||||||
|
}
|
@ -17,10 +17,22 @@ resource "aws_launch_configuration" "control_plane_launch_config" {
|
|||||||
image_id = var.image_id
|
image_id = var.image_id
|
||||||
instance_type = var.instance_type
|
instance_type = var.instance_type
|
||||||
iam_instance_profile = var.iam_instance_profile
|
iam_instance_profile = var.iam_instance_profile
|
||||||
|
security_groups = var.security_groups
|
||||||
metadata_options {
|
metadata_options {
|
||||||
http_tokens = "required"
|
http_tokens = "required"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
root_block_device {
|
||||||
|
encrypted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
ebs_block_device {
|
||||||
|
device_name = "/dev/sdb" # Note: AWS may adjust this to /dev/xvdb, /dev/hdb or /dev/nvme1n1 depending on the disk type. See: https://docs.aws.amazon.com/en_us/AWSEC2/latest/UserGuide/device_naming.html
|
||||||
|
volume_size = var.state_disk_size
|
||||||
|
volume_type = var.state_disk_type
|
||||||
|
encrypted = true
|
||||||
|
delete_on_termination = true
|
||||||
|
}
|
||||||
|
|
||||||
lifecycle {
|
lifecycle {
|
||||||
create_before_destroy = true
|
create_before_destroy = true
|
@ -28,9 +28,14 @@ variable "image_id" {
|
|||||||
description = "Image ID for the nodes."
|
description = "Image ID for the nodes."
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "disk_size" {
|
variable "state_disk_type" {
|
||||||
|
type = string
|
||||||
|
description = "EBS disk type for the state disk of the nodes."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "state_disk_size" {
|
||||||
type = number
|
type = number
|
||||||
description = "Disk size for the nodes, in GB."
|
description = "Disk size for the state disk of the nodes [GB]."
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "target_group_arns" {
|
variable "target_group_arns" {
|
||||||
@ -47,3 +52,8 @@ variable "iam_instance_profile" {
|
|||||||
type = string
|
type = string
|
||||||
description = "IAM instance profile for the nodes."
|
description = "IAM instance profile for the nodes."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "security_groups" {
|
||||||
|
type = list(string)
|
||||||
|
description = "List of IDs of the security groups for an instance."
|
||||||
|
}
|
@ -7,24 +7,12 @@ terraform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_lb" "front_end" {
|
|
||||||
name = var.name
|
|
||||||
internal = false
|
|
||||||
load_balancer_type = "network"
|
|
||||||
subnets = [var.subnet]
|
|
||||||
|
|
||||||
tags = {
|
|
||||||
Name = "loadbalancer"
|
|
||||||
}
|
|
||||||
|
|
||||||
enable_cross_zone_load_balancing = true
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_lb_target_group" "front_end" {
|
resource "aws_lb_target_group" "front_end" {
|
||||||
name = var.name
|
name = var.name
|
||||||
port = var.port
|
port = var.port
|
||||||
protocol = "TCP"
|
protocol = "TCP"
|
||||||
vpc_id = var.vpc
|
vpc_id = var.vpc_id
|
||||||
|
tags = var.tags
|
||||||
|
|
||||||
health_check {
|
health_check {
|
||||||
port = var.port
|
port = var.port
|
||||||
@ -37,9 +25,10 @@ resource "aws_lb_target_group" "front_end" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_lb_listener" "front_end" {
|
resource "aws_lb_listener" "front_end" {
|
||||||
load_balancer_arn = aws_lb.front_end.arn
|
load_balancer_arn = var.lb_arn
|
||||||
port = var.port
|
port = var.port
|
||||||
protocol = "TCP"
|
protocol = "TCP"
|
||||||
|
tags = var.tags
|
||||||
|
|
||||||
default_action {
|
default_action {
|
||||||
type = "forward"
|
type = "forward"
|
@ -0,0 +1,24 @@
|
|||||||
|
variable "name" {
|
||||||
|
type = string
|
||||||
|
description = "Name of the load balancer target."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "port" {
|
||||||
|
type = string
|
||||||
|
description = "Port of the load balancer target."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "vpc_id" {
|
||||||
|
type = string
|
||||||
|
description = "ID of the VPC."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "lb_arn" {
|
||||||
|
type = string
|
||||||
|
description = "ARN of the load balancer."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "tags" {
|
||||||
|
type = map(string)
|
||||||
|
description = "The tags to add to the loadbalancer."
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
aws = {
|
||||||
|
source = "hashicorp/aws"
|
||||||
|
version = "~> 4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_eip" "nat" {
|
||||||
|
vpc = true
|
||||||
|
tags = var.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_subnet" "private" {
|
||||||
|
vpc_id = var.vpc_id
|
||||||
|
cidr_block = var.cidr_vpc_subnet_nodes
|
||||||
|
availability_zone = var.zone
|
||||||
|
tags = merge(var.tags, { Name = "${var.name}-subnet-nodes" })
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_subnet" "public" {
|
||||||
|
vpc_id = var.vpc_id
|
||||||
|
cidr_block = var.cidr_vpc_subnet_internet
|
||||||
|
availability_zone = var.zone
|
||||||
|
tags = merge(var.tags, { Name = "${var.name}-subnet-internet" })
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_internet_gateway" "gw" {
|
||||||
|
vpc_id = var.vpc_id
|
||||||
|
tags = merge(var.tags, { Name = "${var.name}-internet-gateway" })
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_nat_gateway" "gw" {
|
||||||
|
subnet_id = aws_subnet.public.id
|
||||||
|
allocation_id = aws_eip.nat.id
|
||||||
|
tags = merge(var.tags, { Name = "${var.name}-nat-gateway" })
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route_table" "private_nat" {
|
||||||
|
vpc_id = var.vpc_id
|
||||||
|
tags = merge(var.tags, { Name = "${var.name}-private-nat" })
|
||||||
|
|
||||||
|
route {
|
||||||
|
cidr_block = "0.0.0.0/0"
|
||||||
|
gateway_id = aws_nat_gateway.gw.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route_table" "public_igw" {
|
||||||
|
vpc_id = var.vpc_id
|
||||||
|
tags = merge(var.tags, { Name = "${var.name}-public-igw" })
|
||||||
|
|
||||||
|
route {
|
||||||
|
cidr_block = "0.0.0.0/0"
|
||||||
|
gateway_id = aws_internet_gateway.gw.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route_table_association" "private-nat" {
|
||||||
|
subnet_id = aws_subnet.private.id
|
||||||
|
route_table_id = aws_route_table.private_nat.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_route_table_association" "route_to_internet" {
|
||||||
|
subnet_id = aws_subnet.public.id
|
||||||
|
route_table_id = aws_route_table.public_igw.id
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
output "private_subnet_id" {
|
||||||
|
value = aws_subnet.private.id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "public_subnet_id" {
|
||||||
|
value = aws_subnet.public.id
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
variable "name" {
|
||||||
|
type = string
|
||||||
|
description = "Name of your Constellation, which is used as a prefix for tags."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "vpc_id" {
|
||||||
|
type = string
|
||||||
|
description = "ID of the VPC."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "zone" {
|
||||||
|
type = string
|
||||||
|
description = "Availability zone."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cidr_vpc_subnet_nodes" {
|
||||||
|
type = string
|
||||||
|
description = "CIDR block for the subnet that will contain the nodes."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cidr_vpc_subnet_internet" {
|
||||||
|
type = string
|
||||||
|
description = "CIDR block for the subnet that contains resources reachable from the Internet."
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "tags" {
|
||||||
|
type = map(string)
|
||||||
|
description = "The tags to add to the resource."
|
||||||
|
}
|
3
cli/internal/terraform/terraform/aws/outputs.tf
Normal file
3
cli/internal/terraform/terraform/aws/outputs.tf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
output "ip" {
|
||||||
|
value = aws_eip.lb.public_ip
|
||||||
|
}
|
59
cli/internal/terraform/terraform/aws/variables.tf
Normal file
59
cli/internal/terraform/terraform/aws/variables.tf
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
variable "name" {
|
||||||
|
type = string
|
||||||
|
description = "Name of your Constellation"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "iam_instance_profile_worker_nodes" {
|
||||||
|
type = string
|
||||||
|
description = "Name of the IAM instance profile for worker nodes"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "iam_instance_profile_control_plane" {
|
||||||
|
type = string
|
||||||
|
description = "Name of the IAM instance profile for control plane nodes"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "instance_type" {
|
||||||
|
type = string
|
||||||
|
description = "Instance type for worker nodes"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "state_disk_type" {
|
||||||
|
type = string
|
||||||
|
description = "EBS disk type for the state disk of the nodes"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "state_disk_size" {
|
||||||
|
type = number
|
||||||
|
description = "Disk size for the state disk of the nodes [GB]"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "control_plane_count" {
|
||||||
|
type = number
|
||||||
|
description = "Number of control plane nodes"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "worker_count" {
|
||||||
|
type = number
|
||||||
|
description = "Number of worker nodes"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ami" {
|
||||||
|
type = string
|
||||||
|
description = "AMI ID"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "region" {
|
||||||
|
type = string
|
||||||
|
description = "The AWS region to create the cluster in"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "zone" {
|
||||||
|
type = string
|
||||||
|
description = "The AWS availability zone name to create the cluster in"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "debug" {
|
||||||
|
type = bool
|
||||||
|
description = "Enable debug mode. This opens up a debugd port that can be used to deploy a custom bootstrapper."
|
||||||
|
}
|
@ -39,6 +39,28 @@ func (v *CommonVariables) String() string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GCPVariables is user configuration for creating a cluster with Terraform on GCP.
|
||||||
|
type AWSVariables struct {
|
||||||
|
// CommonVariables contains common variables.
|
||||||
|
CommonVariables
|
||||||
|
// Region is the AWS region to use.
|
||||||
|
Region string
|
||||||
|
// Zone is the AWS zone to use in the given region.
|
||||||
|
Zone string
|
||||||
|
// AMIImageID is the ID of the AMI image to use.
|
||||||
|
AMIImageID string
|
||||||
|
// InstanceType is the type of the EC2 instance to use.
|
||||||
|
InstanceType string
|
||||||
|
// StateDiskType is the EBS disk type to use for the state disk.
|
||||||
|
StateDiskType string
|
||||||
|
// IAMGroupControlPlane is the IAM group to use for the control-plane nodes.
|
||||||
|
IAMProfileControlPlane string
|
||||||
|
// IAMGroupWorkerNodes is the IAM group to use for the worker nodes.
|
||||||
|
IAMProfileWorkerNodes string
|
||||||
|
// Debug is true if debug mode is enabled.
|
||||||
|
Debug bool
|
||||||
|
}
|
||||||
|
|
||||||
// GCPVariables is user configuration for creating a cluster with Terraform on GCP.
|
// GCPVariables is user configuration for creating a cluster with Terraform on GCP.
|
||||||
type GCPVariables struct {
|
type GCPVariables struct {
|
||||||
// CommonVariables contains common variables.
|
// CommonVariables contains common variables.
|
||||||
@ -62,6 +84,21 @@ type GCPVariables struct {
|
|||||||
Debug bool
|
Debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *AWSVariables) String() string {
|
||||||
|
b := &strings.Builder{}
|
||||||
|
b.WriteString(v.CommonVariables.String())
|
||||||
|
writeLinef(b, "region = %q", v.Region)
|
||||||
|
writeLinef(b, "zone = %q", v.Zone)
|
||||||
|
writeLinef(b, "ami = %q", v.AMIImageID)
|
||||||
|
writeLinef(b, "instance_type = %q", v.InstanceType)
|
||||||
|
writeLinef(b, "state_disk_type = %q", v.StateDiskType)
|
||||||
|
writeLinef(b, "iam_instance_profile_control_plane = %q", v.IAMProfileControlPlane)
|
||||||
|
writeLinef(b, "iam_instance_profile_worker_nodes = %q", v.IAMProfileWorkerNodes)
|
||||||
|
writeLinef(b, "debug = %t", v.Debug)
|
||||||
|
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
// String returns a string representation of the variables, formatted as Terraform variables.
|
// String returns a string representation of the variables, formatted as Terraform variables.
|
||||||
func (v *GCPVariables) String() string {
|
func (v *GCPVariables) String() string {
|
||||||
b := &strings.Builder{}
|
b := &strings.Builder{}
|
||||||
|
@ -31,6 +31,11 @@ const (
|
|||||||
Version1 = "v1"
|
Version1 = "v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
azureReleaseImageRegex = regexp.MustCompile(`^\/CommunityGalleries\/ConstellationCVM-b3782fa0-0df7-4f2f-963e-fc7fc42663df\/Images\/constellation\/Versions\/[\d]+.[\d]+.[\d]+$`)
|
||||||
|
gcpReleaseImageRegex = regexp.MustCompile(`^projects\/constellation-images\/global\/images\/constellation-v[\d]+-[\d]+-[\d]+$`)
|
||||||
|
)
|
||||||
|
|
||||||
// Config defines configuration used by CLI.
|
// Config defines configuration used by CLI.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// description: |
|
// description: |
|
||||||
@ -84,6 +89,9 @@ type UserKey struct {
|
|||||||
// Fields should remain pointer-types so custom specific configs can nil them
|
// Fields should remain pointer-types so custom specific configs can nil them
|
||||||
// if not required.
|
// if not required.
|
||||||
type ProviderConfig struct {
|
type ProviderConfig struct {
|
||||||
|
// description: |
|
||||||
|
// Configuration for AWS as provider.
|
||||||
|
AWS *AWSConfig `yaml:"aws,omitempty" validate:"omitempty,dive"`
|
||||||
// description: |
|
// description: |
|
||||||
// Configuration for Azure as provider.
|
// Configuration for Azure as provider.
|
||||||
Azure *AzureConfig `yaml:"azure,omitempty" validate:"omitempty,dive"`
|
Azure *AzureConfig `yaml:"azure,omitempty" validate:"omitempty,dive"`
|
||||||
@ -95,6 +103,37 @@ type ProviderConfig struct {
|
|||||||
QEMU *QEMUConfig `yaml:"qemu,omitempty" validate:"omitempty,dive"`
|
QEMU *QEMUConfig `yaml:"qemu,omitempty" validate:"omitempty,dive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AWSConfig are AWS specific configuration values used by the CLI.
|
||||||
|
type AWSConfig struct {
|
||||||
|
// description: |
|
||||||
|
// AWS data center region. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions
|
||||||
|
Region string `yaml:"region" validate:"required"`
|
||||||
|
// description: |
|
||||||
|
// AWS data center zone name in defined region. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-availability-zones
|
||||||
|
Zone string `yaml:"zone" validate:"required"`
|
||||||
|
// description: |
|
||||||
|
// AMI ID of the machine image used to create Constellation nodes.
|
||||||
|
Image string `yaml:"image" validate:"required"`
|
||||||
|
// description: |
|
||||||
|
// VM instance type to use for Constellation nodes. Needs to support NitroTPM. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-prerequisites.html
|
||||||
|
InstanceType string `yaml:"instanceType" validate:"lowercase,aws_instance_type"`
|
||||||
|
// description: |
|
||||||
|
// Type of a node's state disk. The type influences boot time and I/O performance. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html
|
||||||
|
StateDiskType string `yaml:"stateDiskType" validate:"oneof=standard gp2 gp3 st1 sc1 io1"`
|
||||||
|
// description: |
|
||||||
|
// Name of the IAM profile to use for the control plane nodes.
|
||||||
|
IAMProfileControlPlane string `yaml:"iamProfileControlPlane" validate:"required"`
|
||||||
|
// description: |
|
||||||
|
// Name of the IAM profile to use for the worker nodes.
|
||||||
|
IAMProfileWorkerNodes string `yaml:"iamProfileWorkerNodes" validate:"required"`
|
||||||
|
// description: |
|
||||||
|
// Expected VM measurements.
|
||||||
|
Measurements Measurements `yaml:"measurements"`
|
||||||
|
// description: |
|
||||||
|
// List of values that should be enforced to be equal to the ones from the measurement list. Any non-equal values not in this list will only result in a warning.
|
||||||
|
EnforcedMeasurements []uint32 `yaml:"enforcedMeasurements"`
|
||||||
|
}
|
||||||
|
|
||||||
// AzureConfig are Azure specific configuration values used by the CLI.
|
// AzureConfig are Azure specific configuration values used by the CLI.
|
||||||
type AzureConfig struct {
|
type AzureConfig struct {
|
||||||
// description: |
|
// description: |
|
||||||
@ -221,6 +260,16 @@ func Default() *Config {
|
|||||||
StateDiskSizeGB: 30,
|
StateDiskSizeGB: 30,
|
||||||
DebugCluster: func() *bool { b := false; return &b }(),
|
DebugCluster: func() *bool { b := false; return &b }(),
|
||||||
Provider: ProviderConfig{
|
Provider: ProviderConfig{
|
||||||
|
AWS: &AWSConfig{
|
||||||
|
Region: "",
|
||||||
|
Image: "",
|
||||||
|
InstanceType: "m6a.xlarge",
|
||||||
|
StateDiskType: "gp3",
|
||||||
|
IAMProfileControlPlane: "",
|
||||||
|
IAMProfileWorkerNodes: "",
|
||||||
|
Measurements: copyPCRMap(awsPCRs),
|
||||||
|
EnforcedMeasurements: []uint32{}, // TODO: add default values
|
||||||
|
},
|
||||||
Azure: &AzureConfig{
|
Azure: &AzureConfig{
|
||||||
SubscriptionID: "",
|
SubscriptionID: "",
|
||||||
TenantID: "",
|
TenantID: "",
|
||||||
@ -268,6 +317,10 @@ func validateK8sVersion(fl validator.FieldLevel) bool {
|
|||||||
return versions.IsSupportedK8sVersion(fl.Field().String())
|
return versions.IsSupportedK8sVersion(fl.Field().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateAWSInstanceType(fl validator.FieldLevel) bool {
|
||||||
|
return validInstanceTypeForProvider(fl.Field().String(), false, cloudprovider.AWS)
|
||||||
|
}
|
||||||
|
|
||||||
func validateAzureInstanceType(fl validator.FieldLevel) bool {
|
func validateAzureInstanceType(fl validator.FieldLevel) bool {
|
||||||
azureConfig := fl.Parent().Interface().(AzureConfig)
|
azureConfig := fl.Parent().Interface().(AzureConfig)
|
||||||
var acceptNonCVM bool
|
var acceptNonCVM bool
|
||||||
@ -288,6 +341,9 @@ func validateProvider(sl validator.StructLevel) {
|
|||||||
provider := sl.Current().Interface().(ProviderConfig)
|
provider := sl.Current().Interface().(ProviderConfig)
|
||||||
providerCount := 0
|
providerCount := 0
|
||||||
|
|
||||||
|
if provider.AWS != nil {
|
||||||
|
providerCount++
|
||||||
|
}
|
||||||
if provider.Azure != nil {
|
if provider.Azure != nil {
|
||||||
providerCount++
|
providerCount++
|
||||||
}
|
}
|
||||||
@ -314,7 +370,11 @@ func (c *Config) Validate() ([]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register Azure & GCP InstanceType validation error types
|
// Register AWS, Azure & GCP InstanceType validation error types
|
||||||
|
if err := validate.RegisterTranslation("aws_instance_type", trans, registerTranslateAWSInstanceTypeError, translateAWSInstanceTypeError); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if err := validate.RegisterTranslation("azure_instance_type", trans, registerTranslateAzureInstanceTypeError, c.translateAzureInstanceTypeError); err != nil {
|
if err := validate.RegisterTranslation("azure_instance_type", trans, registerTranslateAzureInstanceTypeError, c.translateAzureInstanceTypeError); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -337,12 +397,17 @@ func (c *Config) Validate() ([]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// register custom validator with label azure_instance_type to validate version based on available versionConfigs.
|
// register custom validator with label aws_instance_type to validate the AWS instance type from config input.
|
||||||
|
if err := validate.RegisterValidation("aws_instance_type", validateAWSInstanceType); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// register custom validator with label azure_instance_type to validate the Azure instance type from config input.
|
||||||
if err := validate.RegisterValidation("azure_instance_type", validateAzureInstanceType); err != nil {
|
if err := validate.RegisterValidation("azure_instance_type", validateAzureInstanceType); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// register custom validator with label gcp_instance_type to validate version based on available versionConfigs.
|
// register custom validator with label gcp_instance_type to validate the GCP instance type from config input.
|
||||||
if err := validate.RegisterValidation("gcp_instance_type", validateGCPInstanceType); err != nil {
|
if err := validate.RegisterValidation("gcp_instance_type", validateGCPInstanceType); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -384,6 +449,16 @@ func (c *Config) translateAzureInstanceTypeError(ut ut.Translator, fe validator.
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerTranslateAWSInstanceTypeError(ut ut.Translator) error {
|
||||||
|
return ut.Add("aws_instance_type", fmt.Sprintf("{0} must be an instance from one of the following families types with size xlarge or higher: %v", instancetypes.AWSSupportedInstanceFamilies), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func translateAWSInstanceTypeError(ut ut.Translator, fe validator.FieldError) string {
|
||||||
|
t, _ := ut.T("aws_instance_type", fe.Field())
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
func registerTranslateGCPInstanceTypeError(ut ut.Translator) error {
|
func registerTranslateGCPInstanceTypeError(ut ut.Translator) error {
|
||||||
return ut.Add("gcp_instance_type", fmt.Sprintf("{0} must be one of %v", instancetypes.GCPInstanceTypes), true)
|
return ut.Add("gcp_instance_type", fmt.Sprintf("{0} must be one of %v", instancetypes.GCPInstanceTypes), true)
|
||||||
}
|
}
|
||||||
@ -413,6 +488,9 @@ func (c *Config) translateMoreThanOneProviderError(ut ut.Translator, fe validato
|
|||||||
definedProviders := make([]string, 0)
|
definedProviders := make([]string, 0)
|
||||||
|
|
||||||
// c.Provider should not be nil as Provider would need to be defined for the validation to fail in this place.
|
// c.Provider should not be nil as Provider would need to be defined for the validation to fail in this place.
|
||||||
|
if c.Provider.AWS != nil {
|
||||||
|
definedProviders = append(definedProviders, "AWS")
|
||||||
|
}
|
||||||
if c.Provider.Azure != nil {
|
if c.Provider.Azure != nil {
|
||||||
definedProviders = append(definedProviders, "Azure")
|
definedProviders = append(definedProviders, "Azure")
|
||||||
}
|
}
|
||||||
@ -432,6 +510,8 @@ func (c *Config) translateMoreThanOneProviderError(ut ut.Translator, fe validato
|
|||||||
// HasProvider checks whether the config contains the provider.
|
// HasProvider checks whether the config contains the provider.
|
||||||
func (c *Config) HasProvider(provider cloudprovider.Provider) bool {
|
func (c *Config) HasProvider(provider cloudprovider.Provider) bool {
|
||||||
switch provider {
|
switch provider {
|
||||||
|
case cloudprovider.AWS:
|
||||||
|
return c.Provider.AWS != nil
|
||||||
case cloudprovider.Azure:
|
case cloudprovider.Azure:
|
||||||
return c.Provider.Azure != nil
|
return c.Provider.Azure != nil
|
||||||
case cloudprovider.GCP:
|
case cloudprovider.GCP:
|
||||||
@ -446,6 +526,9 @@ func (c *Config) HasProvider(provider cloudprovider.Provider) bool {
|
|||||||
// If multiple cloud providers are configured (which is not supported)
|
// If multiple cloud providers are configured (which is not supported)
|
||||||
// only a single image is returned.
|
// only a single image is returned.
|
||||||
func (c *Config) Image() string {
|
func (c *Config) Image() string {
|
||||||
|
if c.HasProvider(cloudprovider.AWS) {
|
||||||
|
return c.Provider.AWS.Image
|
||||||
|
}
|
||||||
if c.HasProvider(cloudprovider.Azure) {
|
if c.HasProvider(cloudprovider.Azure) {
|
||||||
return c.Provider.Azure.Image
|
return c.Provider.Azure.Image
|
||||||
}
|
}
|
||||||
@ -456,6 +539,9 @@ func (c *Config) Image() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) UpdateMeasurements(newMeasurements Measurements) {
|
func (c *Config) UpdateMeasurements(newMeasurements Measurements) {
|
||||||
|
if c.Provider.AWS != nil {
|
||||||
|
c.Provider.AWS.Measurements.CopyFrom(newMeasurements)
|
||||||
|
}
|
||||||
if c.Provider.Azure != nil {
|
if c.Provider.Azure != nil {
|
||||||
c.Provider.Azure.Measurements.CopyFrom(newMeasurements)
|
c.Provider.Azure.Measurements.CopyFrom(newMeasurements)
|
||||||
}
|
}
|
||||||
@ -474,6 +560,8 @@ func (c *Config) RemoveProviderExcept(provider cloudprovider.Provider) {
|
|||||||
currentProviderConfigs := c.Provider
|
currentProviderConfigs := c.Provider
|
||||||
c.Provider = ProviderConfig{}
|
c.Provider = ProviderConfig{}
|
||||||
switch provider {
|
switch provider {
|
||||||
|
case cloudprovider.AWS:
|
||||||
|
c.Provider.AWS = currentProviderConfigs.AWS
|
||||||
case cloudprovider.Azure:
|
case cloudprovider.Azure:
|
||||||
c.Provider.Azure = currentProviderConfigs.Azure
|
c.Provider.Azure = currentProviderConfigs.Azure
|
||||||
case cloudprovider.GCP:
|
case cloudprovider.GCP:
|
||||||
@ -490,12 +578,13 @@ func (c *Config) RemoveProviderExcept(provider cloudprovider.Provider) {
|
|||||||
// was put inside an image just by looking at its name.
|
// was put inside an image just by looking at its name.
|
||||||
func (c *Config) IsDebugImage() bool {
|
func (c *Config) IsDebugImage() bool {
|
||||||
switch {
|
switch {
|
||||||
case c.Provider.GCP != nil:
|
case c.Provider.AWS != nil:
|
||||||
gcpRegex := regexp.MustCompile(`^projects\/constellation-images\/global\/images\/constellation-v[\d]+-[\d]+-[\d]+$`)
|
// TODO: Add proper image name validation for AWS when we are closer to release.
|
||||||
return !gcpRegex.MatchString(c.Provider.GCP.Image)
|
return true
|
||||||
case c.Provider.Azure != nil:
|
case c.Provider.Azure != nil:
|
||||||
azureRegex := regexp.MustCompile(`^\/CommunityGalleries\/ConstellationCVM-b3782fa0-0df7-4f2f-963e-fc7fc42663df\/Images\/constellation\/Versions\/[\d]+.[\d]+.[\d]+$`)
|
return !azureReleaseImageRegex.MatchString(c.Provider.Azure.Image)
|
||||||
return !azureRegex.MatchString(c.Provider.Azure.Image)
|
case c.Provider.GCP != nil:
|
||||||
|
return !gcpReleaseImageRegex.MatchString(c.Provider.GCP.Image)
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -503,6 +592,9 @@ func (c *Config) IsDebugImage() bool {
|
|||||||
|
|
||||||
// GetProvider returns the configured cloud provider.
|
// GetProvider returns the configured cloud provider.
|
||||||
func (c *Config) GetProvider() cloudprovider.Provider {
|
func (c *Config) GetProvider() cloudprovider.Provider {
|
||||||
|
if c.Provider.AWS != nil {
|
||||||
|
return cloudprovider.AWS
|
||||||
|
}
|
||||||
if c.Provider.Azure != nil {
|
if c.Provider.Azure != nil {
|
||||||
return cloudprovider.Azure
|
return cloudprovider.Azure
|
||||||
}
|
}
|
||||||
@ -545,13 +637,8 @@ func copyPCRMap(m map[uint32][]byte) map[uint32][]byte {
|
|||||||
|
|
||||||
func validInstanceTypeForProvider(insType string, acceptNonCVM bool, provider cloudprovider.Provider) bool {
|
func validInstanceTypeForProvider(insType string, acceptNonCVM bool, provider cloudprovider.Provider) bool {
|
||||||
switch provider {
|
switch provider {
|
||||||
case cloudprovider.GCP:
|
case cloudprovider.AWS:
|
||||||
for _, instanceType := range instancetypes.GCPInstanceTypes {
|
return checkIfAWSInstanceTypeIsValid(insType)
|
||||||
if insType == instanceType {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
case cloudprovider.Azure:
|
case cloudprovider.Azure:
|
||||||
if acceptNonCVM {
|
if acceptNonCVM {
|
||||||
for _, instanceType := range instancetypes.AzureTrustedLaunchInstanceTypes {
|
for _, instanceType := range instancetypes.AzureTrustedLaunchInstanceTypes {
|
||||||
@ -567,11 +654,58 @@ func validInstanceTypeForProvider(insType string, acceptNonCVM bool, provider cl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
case cloudprovider.GCP:
|
||||||
|
for _, instanceType := range instancetypes.GCPInstanceTypes {
|
||||||
|
if insType == instanceType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkIfAWSInstanceTypeIsValid checks if an AWS instance type passed as user input is in one of the instance families supporting NitroTPM.
|
||||||
|
func checkIfAWSInstanceTypeIsValid(userInput string) bool {
|
||||||
|
// Check if user or code does anything weird and tries to pass multiple strings as one
|
||||||
|
if strings.Contains(userInput, " ") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if strings.Contains(userInput, ",") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if strings.Contains(userInput, ";") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
splitInstanceType := strings.Split(userInput, ".")
|
||||||
|
|
||||||
|
if len(splitInstanceType) != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
userDefinedFamily := splitInstanceType[0]
|
||||||
|
userDefinedSize := splitInstanceType[1]
|
||||||
|
|
||||||
|
// Check if instace type has at least 4 vCPUs (= contains "xlarge" in its name)
|
||||||
|
hasEnoughVCPUs := strings.Contains(userDefinedSize, "xlarge")
|
||||||
|
if !hasEnoughVCPUs {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check if the user input is a supported family
|
||||||
|
// Note that we cannot directly use the family split from the Graviton check above, as some instances are directly specified by their full name and not just the family in general
|
||||||
|
for _, supportedFamily := range instancetypes.AWSSupportedInstanceFamilies {
|
||||||
|
supportedFamilyLowercase := strings.ToLower(supportedFamily)
|
||||||
|
if userDefinedFamily == supportedFamilyLowercase {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// IsDebugCluster checks whether the cluster is configured as a debug cluster.
|
// IsDebugCluster checks whether the cluster is configured as a debug cluster.
|
||||||
func (c *Config) IsDebugCluster() bool {
|
func (c *Config) IsDebugCluster() bool {
|
||||||
if c.DebugCluster != nil && *c.DebugCluster {
|
if c.DebugCluster != nil && *c.DebugCluster {
|
||||||
|
@ -15,6 +15,7 @@ var (
|
|||||||
UpgradeConfigDoc encoder.Doc
|
UpgradeConfigDoc encoder.Doc
|
||||||
UserKeyDoc encoder.Doc
|
UserKeyDoc encoder.Doc
|
||||||
ProviderConfigDoc encoder.Doc
|
ProviderConfigDoc encoder.Doc
|
||||||
|
AWSConfigDoc encoder.Doc
|
||||||
AzureConfigDoc encoder.Doc
|
AzureConfigDoc encoder.Doc
|
||||||
GCPConfigDoc encoder.Doc
|
GCPConfigDoc encoder.Doc
|
||||||
QEMUConfigDoc encoder.Doc
|
QEMUConfigDoc encoder.Doc
|
||||||
@ -120,22 +121,83 @@ func init() {
|
|||||||
FieldName: "provider",
|
FieldName: "provider",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ProviderConfigDoc.Fields = make([]encoder.Doc, 3)
|
ProviderConfigDoc.Fields = make([]encoder.Doc, 4)
|
||||||
ProviderConfigDoc.Fields[0].Name = "azure"
|
ProviderConfigDoc.Fields[0].Name = "aws"
|
||||||
ProviderConfigDoc.Fields[0].Type = "AzureConfig"
|
ProviderConfigDoc.Fields[0].Type = "AWSConfig"
|
||||||
ProviderConfigDoc.Fields[0].Note = ""
|
ProviderConfigDoc.Fields[0].Note = ""
|
||||||
ProviderConfigDoc.Fields[0].Description = "Configuration for Azure as provider."
|
ProviderConfigDoc.Fields[0].Description = "Configuration for AWS as provider."
|
||||||
ProviderConfigDoc.Fields[0].Comments[encoder.LineComment] = "Configuration for Azure as provider."
|
ProviderConfigDoc.Fields[0].Comments[encoder.LineComment] = "Configuration for AWS as provider."
|
||||||
ProviderConfigDoc.Fields[1].Name = "gcp"
|
ProviderConfigDoc.Fields[1].Name = "azure"
|
||||||
ProviderConfigDoc.Fields[1].Type = "GCPConfig"
|
ProviderConfigDoc.Fields[1].Type = "AzureConfig"
|
||||||
ProviderConfigDoc.Fields[1].Note = ""
|
ProviderConfigDoc.Fields[1].Note = ""
|
||||||
ProviderConfigDoc.Fields[1].Description = "Configuration for Google Cloud as provider."
|
ProviderConfigDoc.Fields[1].Description = "Configuration for Azure as provider."
|
||||||
ProviderConfigDoc.Fields[1].Comments[encoder.LineComment] = "Configuration for Google Cloud as provider."
|
ProviderConfigDoc.Fields[1].Comments[encoder.LineComment] = "Configuration for Azure as provider."
|
||||||
ProviderConfigDoc.Fields[2].Name = "qemu"
|
ProviderConfigDoc.Fields[2].Name = "gcp"
|
||||||
ProviderConfigDoc.Fields[2].Type = "QEMUConfig"
|
ProviderConfigDoc.Fields[2].Type = "GCPConfig"
|
||||||
ProviderConfigDoc.Fields[2].Note = ""
|
ProviderConfigDoc.Fields[2].Note = ""
|
||||||
ProviderConfigDoc.Fields[2].Description = "Configuration for QEMU as provider."
|
ProviderConfigDoc.Fields[2].Description = "Configuration for Google Cloud as provider."
|
||||||
ProviderConfigDoc.Fields[2].Comments[encoder.LineComment] = "Configuration for QEMU as provider."
|
ProviderConfigDoc.Fields[2].Comments[encoder.LineComment] = "Configuration for Google Cloud as provider."
|
||||||
|
ProviderConfigDoc.Fields[3].Name = "qemu"
|
||||||
|
ProviderConfigDoc.Fields[3].Type = "QEMUConfig"
|
||||||
|
ProviderConfigDoc.Fields[3].Note = ""
|
||||||
|
ProviderConfigDoc.Fields[3].Description = "Configuration for QEMU as provider."
|
||||||
|
ProviderConfigDoc.Fields[3].Comments[encoder.LineComment] = "Configuration for QEMU as provider."
|
||||||
|
|
||||||
|
AWSConfigDoc.Type = "AWSConfig"
|
||||||
|
AWSConfigDoc.Comments[encoder.LineComment] = "AWSConfig are AWS specific configuration values used by the CLI."
|
||||||
|
AWSConfigDoc.Description = "AWSConfig are AWS specific configuration values used by the CLI."
|
||||||
|
AWSConfigDoc.AppearsIn = []encoder.Appearance{
|
||||||
|
{
|
||||||
|
TypeName: "ProviderConfig",
|
||||||
|
FieldName: "aws",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
AWSConfigDoc.Fields = make([]encoder.Doc, 9)
|
||||||
|
AWSConfigDoc.Fields[0].Name = "region"
|
||||||
|
AWSConfigDoc.Fields[0].Type = "string"
|
||||||
|
AWSConfigDoc.Fields[0].Note = ""
|
||||||
|
AWSConfigDoc.Fields[0].Description = "AWS data center region. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions"
|
||||||
|
AWSConfigDoc.Fields[0].Comments[encoder.LineComment] = "AWS data center region. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions"
|
||||||
|
AWSConfigDoc.Fields[1].Name = "zone"
|
||||||
|
AWSConfigDoc.Fields[1].Type = "string"
|
||||||
|
AWSConfigDoc.Fields[1].Note = ""
|
||||||
|
AWSConfigDoc.Fields[1].Description = "AWS data center zone name in defined region. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-availability-zones"
|
||||||
|
AWSConfigDoc.Fields[1].Comments[encoder.LineComment] = "AWS data center zone name in defined region. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-availability-zones"
|
||||||
|
AWSConfigDoc.Fields[2].Name = "image"
|
||||||
|
AWSConfigDoc.Fields[2].Type = "string"
|
||||||
|
AWSConfigDoc.Fields[2].Note = ""
|
||||||
|
AWSConfigDoc.Fields[2].Description = "AMI ID of the machine image used to create Constellation nodes."
|
||||||
|
AWSConfigDoc.Fields[2].Comments[encoder.LineComment] = "AMI ID of the machine image used to create Constellation nodes."
|
||||||
|
AWSConfigDoc.Fields[3].Name = "instanceType"
|
||||||
|
AWSConfigDoc.Fields[3].Type = "string"
|
||||||
|
AWSConfigDoc.Fields[3].Note = ""
|
||||||
|
AWSConfigDoc.Fields[3].Description = "VM instance type to use for Constellation nodes. Needs to support NitroTPM. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-prerequisites.html"
|
||||||
|
AWSConfigDoc.Fields[3].Comments[encoder.LineComment] = "VM instance type to use for Constellation nodes. Needs to support NitroTPM. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-prerequisites.html"
|
||||||
|
AWSConfigDoc.Fields[4].Name = "stateDiskType"
|
||||||
|
AWSConfigDoc.Fields[4].Type = "string"
|
||||||
|
AWSConfigDoc.Fields[4].Note = ""
|
||||||
|
AWSConfigDoc.Fields[4].Description = "Type of a node's state disk. The type influences boot time and I/O performance. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html"
|
||||||
|
AWSConfigDoc.Fields[4].Comments[encoder.LineComment] = "Type of a node's state disk. The type influences boot time and I/O performance. See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html"
|
||||||
|
AWSConfigDoc.Fields[5].Name = "iamProfileControlPlane"
|
||||||
|
AWSConfigDoc.Fields[5].Type = "string"
|
||||||
|
AWSConfigDoc.Fields[5].Note = ""
|
||||||
|
AWSConfigDoc.Fields[5].Description = "Name of the IAM profile to use for the control plane nodes."
|
||||||
|
AWSConfigDoc.Fields[5].Comments[encoder.LineComment] = "Name of the IAM profile to use for the control plane nodes."
|
||||||
|
AWSConfigDoc.Fields[6].Name = "iamProfileWorkerNodes"
|
||||||
|
AWSConfigDoc.Fields[6].Type = "string"
|
||||||
|
AWSConfigDoc.Fields[6].Note = ""
|
||||||
|
AWSConfigDoc.Fields[6].Description = "Name of the IAM profile to use for the worker nodes."
|
||||||
|
AWSConfigDoc.Fields[6].Comments[encoder.LineComment] = "Name of the IAM profile to use for the worker nodes."
|
||||||
|
AWSConfigDoc.Fields[7].Name = "measurements"
|
||||||
|
AWSConfigDoc.Fields[7].Type = "Measurements"
|
||||||
|
AWSConfigDoc.Fields[7].Note = ""
|
||||||
|
AWSConfigDoc.Fields[7].Description = "Expected VM measurements."
|
||||||
|
AWSConfigDoc.Fields[7].Comments[encoder.LineComment] = "Expected VM measurements."
|
||||||
|
AWSConfigDoc.Fields[8].Name = "enforcedMeasurements"
|
||||||
|
AWSConfigDoc.Fields[8].Type = "[]uint32"
|
||||||
|
AWSConfigDoc.Fields[8].Note = ""
|
||||||
|
AWSConfigDoc.Fields[8].Description = "List of values that should be enforced to be equal to the ones from the measurement list. Any non-equal values not in this list will only result in a warning."
|
||||||
|
AWSConfigDoc.Fields[8].Comments[encoder.LineComment] = "List of values that should be enforced to be equal to the ones from the measurement list. Any non-equal values not in this list will only result in a warning."
|
||||||
|
|
||||||
AzureConfigDoc.Type = "AzureConfig"
|
AzureConfigDoc.Type = "AzureConfig"
|
||||||
AzureConfigDoc.Comments[encoder.LineComment] = "AzureConfig are Azure specific configuration values used by the CLI."
|
AzureConfigDoc.Comments[encoder.LineComment] = "AzureConfig are Azure specific configuration values used by the CLI."
|
||||||
@ -367,6 +429,10 @@ func (_ ProviderConfig) Doc() *encoder.Doc {
|
|||||||
return &ProviderConfigDoc
|
return &ProviderConfigDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (_ AWSConfig) Doc() *encoder.Doc {
|
||||||
|
return &AWSConfigDoc
|
||||||
|
}
|
||||||
|
|
||||||
func (_ AzureConfig) Doc() *encoder.Doc {
|
func (_ AzureConfig) Doc() *encoder.Doc {
|
||||||
return &AzureConfigDoc
|
return &AzureConfigDoc
|
||||||
}
|
}
|
||||||
@ -389,6 +455,7 @@ func GetConfigurationDoc() *encoder.FileDoc {
|
|||||||
&UpgradeConfigDoc,
|
&UpgradeConfigDoc,
|
||||||
&UserKeyDoc,
|
&UserKeyDoc,
|
||||||
&ProviderConfigDoc,
|
&ProviderConfigDoc,
|
||||||
|
&AWSConfigDoc,
|
||||||
&AzureConfigDoc,
|
&AzureConfigDoc,
|
||||||
&GCPConfigDoc,
|
&GCPConfigDoc,
|
||||||
&QEMUConfigDoc,
|
&QEMUConfigDoc,
|
||||||
|
@ -109,7 +109,7 @@ func TestFromFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValidate(t *testing.T) {
|
func TestValidate(t *testing.T) {
|
||||||
const defaultMsgCount = 15 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default
|
const defaultMsgCount = 20 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
cnf *Config
|
cnf *Config
|
||||||
@ -170,6 +170,10 @@ func TestImage(t *testing.T) {
|
|||||||
cfg *Config
|
cfg *Config
|
||||||
wantImage string
|
wantImage string
|
||||||
}{
|
}{
|
||||||
|
"default aws": {
|
||||||
|
cfg: func() *Config { c := Default(); c.RemoveProviderExcept(cloudprovider.AWS); return c }(),
|
||||||
|
wantImage: Default().Provider.AWS.Image,
|
||||||
|
},
|
||||||
"default azure": {
|
"default azure": {
|
||||||
cfg: func() *Config { c := Default(); c.RemoveProviderExcept(cloudprovider.Azure); return c }(),
|
cfg: func() *Config { c := Default(); c.RemoveProviderExcept(cloudprovider.Azure); return c }(),
|
||||||
wantImage: Default().Provider.Azure.Image,
|
wantImage: Default().Provider.Azure.Image,
|
||||||
@ -197,10 +201,15 @@ func TestImage(t *testing.T) {
|
|||||||
func TestConfigRemoveProviderExcept(t *testing.T) {
|
func TestConfigRemoveProviderExcept(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
removeExcept cloudprovider.Provider
|
removeExcept cloudprovider.Provider
|
||||||
|
wantAWS *AWSConfig
|
||||||
wantAzure *AzureConfig
|
wantAzure *AzureConfig
|
||||||
wantGCP *GCPConfig
|
wantGCP *GCPConfig
|
||||||
wantQEMU *QEMUConfig
|
wantQEMU *QEMUConfig
|
||||||
}{
|
}{
|
||||||
|
"except aws": {
|
||||||
|
removeExcept: cloudprovider.AWS,
|
||||||
|
wantAWS: Default().Provider.AWS,
|
||||||
|
},
|
||||||
"except azure": {
|
"except azure": {
|
||||||
removeExcept: cloudprovider.Azure,
|
removeExcept: cloudprovider.Azure,
|
||||||
wantAzure: Default().Provider.Azure,
|
wantAzure: Default().Provider.Azure,
|
||||||
@ -215,6 +224,7 @@ func TestConfigRemoveProviderExcept(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"unknown provider": {
|
"unknown provider": {
|
||||||
removeExcept: cloudprovider.Unknown,
|
removeExcept: cloudprovider.Unknown,
|
||||||
|
wantAWS: Default().Provider.AWS,
|
||||||
wantAzure: Default().Provider.Azure,
|
wantAzure: Default().Provider.Azure,
|
||||||
wantGCP: Default().Provider.GCP,
|
wantGCP: Default().Provider.GCP,
|
||||||
wantQEMU: Default().Provider.QEMU,
|
wantQEMU: Default().Provider.QEMU,
|
||||||
@ -228,6 +238,7 @@ func TestConfigRemoveProviderExcept(t *testing.T) {
|
|||||||
conf := Default()
|
conf := Default()
|
||||||
conf.RemoveProviderExcept(tc.removeExcept)
|
conf.RemoveProviderExcept(tc.removeExcept)
|
||||||
|
|
||||||
|
assert.Equal(tc.wantAWS, conf.Provider.AWS)
|
||||||
assert.Equal(tc.wantAzure, conf.Provider.Azure)
|
assert.Equal(tc.wantAzure, conf.Provider.Azure)
|
||||||
assert.Equal(tc.wantGCP, conf.Provider.GCP)
|
assert.Equal(tc.wantGCP, conf.Provider.GCP)
|
||||||
assert.Equal(tc.wantQEMU, conf.Provider.QEMU)
|
assert.Equal(tc.wantQEMU, conf.Provider.QEMU)
|
||||||
@ -256,6 +267,15 @@ func TestConfig_UpdateMeasurements(t *testing.T) {
|
|||||||
3: []byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
|
3: []byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // AWS
|
||||||
|
conf := Default()
|
||||||
|
conf.RemoveProviderExcept(cloudprovider.AWS)
|
||||||
|
for k := range conf.Provider.AWS.Measurements {
|
||||||
|
delete(conf.Provider.AWS.Measurements, k)
|
||||||
|
}
|
||||||
|
conf.UpdateMeasurements(newMeasurements)
|
||||||
|
assert.Equal(newMeasurements, conf.Provider.AWS.Measurements)
|
||||||
|
}
|
||||||
{ // Azure
|
{ // Azure
|
||||||
conf := Default()
|
conf := Default()
|
||||||
conf.RemoveProviderExcept(cloudprovider.Azure)
|
conf.RemoveProviderExcept(cloudprovider.Azure)
|
||||||
@ -290,6 +310,7 @@ func TestConfig_IsImageDebug(t *testing.T) {
|
|||||||
conf *Config
|
conf *Config
|
||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
|
// TODO: Add AWS when we know the format of published images & debug images
|
||||||
"gcp release": {
|
"gcp release": {
|
||||||
conf: func() *Config {
|
conf: func() *Config {
|
||||||
conf := Default()
|
conf := Default()
|
||||||
@ -352,6 +373,11 @@ func TestValidInstanceTypeForProvider(t *testing.T) {
|
|||||||
instanceTypes: []string{},
|
instanceTypes: []string{},
|
||||||
expectedResult: false,
|
expectedResult: false,
|
||||||
},
|
},
|
||||||
|
"empty aws": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{},
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
"empty azure only CVMs": {
|
"empty azure only CVMs": {
|
||||||
provider: cloudprovider.Azure,
|
provider: cloudprovider.Azure,
|
||||||
instanceTypes: []string{},
|
instanceTypes: []string{},
|
||||||
@ -384,7 +410,7 @@ func TestValidInstanceTypeForProvider(t *testing.T) {
|
|||||||
instanceTypes: instancetypes.AzureTrustedLaunchInstanceTypes,
|
instanceTypes: instancetypes.AzureTrustedLaunchInstanceTypes,
|
||||||
expectedResult: false,
|
expectedResult: false,
|
||||||
},
|
},
|
||||||
"azure trusted launch VMs with CVMs disbled": {
|
"azure trusted launch VMs with CVMs disabled": {
|
||||||
provider: cloudprovider.Azure,
|
provider: cloudprovider.Azure,
|
||||||
instanceTypes: instancetypes.AzureTrustedLaunchInstanceTypes,
|
instanceTypes: instancetypes.AzureTrustedLaunchInstanceTypes,
|
||||||
nonCVMsAllowed: true,
|
nonCVMsAllowed: true,
|
||||||
@ -417,6 +443,28 @@ func TestValidInstanceTypeForProvider(t *testing.T) {
|
|||||||
nonCVMsAllowed: true,
|
nonCVMsAllowed: true,
|
||||||
expectedResult: false,
|
expectedResult: false,
|
||||||
},
|
},
|
||||||
|
// Testing every possible instance type for AWS is not feasible, so we just test a few based on known supported / unsupported families
|
||||||
|
// Also serves as a test for checkIfInstanceInValidAWSFamilys
|
||||||
|
"aws two valid instances": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{"c5.xlarge", "c5a.2xlarge", "c5a.16xlarge", "u-12tb1.112xlarge"},
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
"aws one valid instance one with too little vCPUs": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{"c5.medium"},
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
"aws graviton sub-family unsupported": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{"m6g.xlarge", "r6g.2xlarge", "x2gd.xlarge", "g5g.8xlarge"},
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
"aws combined two valid instances as one string": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{"c5.xlarge, c5a.2xlarge"},
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for name, tc := range testCases {
|
for name, tc := range testCases {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
|
50
internal/config/instancetypes/aws.go
Normal file
50
internal/config/instancetypes/aws.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package instancetypes
|
||||||
|
|
||||||
|
// Derived from: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-prerequisites.html (Last updated: October 20th, 2022).
|
||||||
|
var AWSSupportedInstanceFamilies = []string{
|
||||||
|
"C5",
|
||||||
|
"C5a",
|
||||||
|
"C5ad",
|
||||||
|
"C5d",
|
||||||
|
"C5n",
|
||||||
|
"C6i",
|
||||||
|
"D3",
|
||||||
|
"D3en",
|
||||||
|
"G4dn",
|
||||||
|
"G5",
|
||||||
|
"Hpc6a",
|
||||||
|
"I3en",
|
||||||
|
"I4i",
|
||||||
|
"Inf1",
|
||||||
|
"M5",
|
||||||
|
"M5a",
|
||||||
|
"M5ad",
|
||||||
|
"M5d",
|
||||||
|
"M5dn",
|
||||||
|
"M5n",
|
||||||
|
"M5zn",
|
||||||
|
"M6a",
|
||||||
|
"M6i",
|
||||||
|
"R5",
|
||||||
|
"R5a",
|
||||||
|
"R5ad",
|
||||||
|
"R5b",
|
||||||
|
"R5d",
|
||||||
|
"R5dn",
|
||||||
|
"R5n",
|
||||||
|
"R6i",
|
||||||
|
"U-3tb1",
|
||||||
|
"U-6tb1",
|
||||||
|
"U-9tb1",
|
||||||
|
"U-12tb1",
|
||||||
|
"X2idn",
|
||||||
|
"X2iedn",
|
||||||
|
"X2iezn",
|
||||||
|
"z1d",
|
||||||
|
}
|
@ -43,6 +43,12 @@ var (
|
|||||||
uint32(vtpm.PCRIndexClusterID): zero,
|
uint32(vtpm.PCRIndexClusterID): zero,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// awsPCRs are the PCR values for an AWS Nitro Constellation node that are initially set in a generated config file.
|
||||||
|
awsPCRs = Measurements{
|
||||||
|
uint32(vtpm.PCRIndexOwnerID): {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||||
|
uint32(vtpm.PCRIndexClusterID): {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||||
|
}
|
||||||
|
|
||||||
qemuPCRs = Measurements{
|
qemuPCRs = Measurements{
|
||||||
11: zero,
|
11: zero,
|
||||||
12: zero,
|
12: zero,
|
||||||
|
@ -1,189 +0,0 @@
|
|||||||
terraform {
|
|
||||||
required_providers {
|
|
||||||
aws = {
|
|
||||||
source = "hashicorp/aws"
|
|
||||||
version = "~> 4.0"
|
|
||||||
}
|
|
||||||
random = {
|
|
||||||
source = "hashicorp/random"
|
|
||||||
version = "3.4.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Configure the AWS Provider
|
|
||||||
provider "aws" {
|
|
||||||
region = var.region
|
|
||||||
}
|
|
||||||
|
|
||||||
locals {
|
|
||||||
uid = random_id.uid.hex
|
|
||||||
name = "${var.name}-${local.uid}"
|
|
||||||
tag = "constellation-${local.uid}"
|
|
||||||
ports_node_range = "30000-32767"
|
|
||||||
ports_ssh = "22"
|
|
||||||
|
|
||||||
ports_kubernetes = "6443"
|
|
||||||
ports_bootstrapper = "9000"
|
|
||||||
ports_konnectivity = "8132"
|
|
||||||
ports_verify = "30081"
|
|
||||||
ports_debugd = "4000"
|
|
||||||
|
|
||||||
cidr_vpc_subnet_nodes = "192.168.178.0/24"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "random_id" "uid" {
|
|
||||||
byte_length = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_vpc" "vpc" {
|
|
||||||
cidr_block = "192.168.0.0/16"
|
|
||||||
tags = {
|
|
||||||
Name = "${local.name}-vpc"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_subnet" "main" {
|
|
||||||
vpc_id = aws_vpc.vpc.id
|
|
||||||
cidr_block = local.cidr_vpc_subnet_nodes
|
|
||||||
tags = {
|
|
||||||
Name = "${local.name}-subnet"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_internet_gateway" "gw" {
|
|
||||||
vpc_id = aws_vpc.vpc.id
|
|
||||||
|
|
||||||
tags = {
|
|
||||||
Name = "${local.name}-gateway"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_security_group" "security_group" {
|
|
||||||
name = local.name
|
|
||||||
vpc_id = aws_vpc.vpc.id
|
|
||||||
description = "Security group for ${local.name}"
|
|
||||||
|
|
||||||
egress {
|
|
||||||
from_port = 0
|
|
||||||
to_port = 0
|
|
||||||
protocol = "-1"
|
|
||||||
cidr_blocks = ["0.0.0.0/0"]
|
|
||||||
description = "Allow all outbound traffic"
|
|
||||||
}
|
|
||||||
|
|
||||||
ingress {
|
|
||||||
from_port = split("-", local.ports_node_range)[0]
|
|
||||||
to_port = split("-", local.ports_node_range)[1]
|
|
||||||
protocol = "tcp"
|
|
||||||
cidr_blocks = ["0.0.0.0/0"]
|
|
||||||
description = "K8s node ports"
|
|
||||||
}
|
|
||||||
|
|
||||||
ingress {
|
|
||||||
from_port = local.ports_bootstrapper
|
|
||||||
to_port = local.ports_bootstrapper
|
|
||||||
protocol = "tcp"
|
|
||||||
cidr_blocks = ["0.0.0.0/0"]
|
|
||||||
description = "bootstrapper"
|
|
||||||
}
|
|
||||||
|
|
||||||
ingress {
|
|
||||||
from_port = local.ports_kubernetes
|
|
||||||
to_port = local.ports_kubernetes
|
|
||||||
protocol = "tcp"
|
|
||||||
cidr_blocks = ["0.0.0.0/0"]
|
|
||||||
description = "kubernetes"
|
|
||||||
}
|
|
||||||
|
|
||||||
ingress {
|
|
||||||
from_port = local.ports_konnectivity
|
|
||||||
to_port = local.ports_konnectivity
|
|
||||||
protocol = "tcp"
|
|
||||||
cidr_blocks = ["0.0.0.0/0"]
|
|
||||||
description = "konnectivity"
|
|
||||||
}
|
|
||||||
|
|
||||||
ingress {
|
|
||||||
from_port = local.ports_debugd
|
|
||||||
to_port = local.ports_debugd
|
|
||||||
protocol = "tcp"
|
|
||||||
cidr_blocks = ["0.0.0.0/0"]
|
|
||||||
description = "debugd"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
module "load_balancer_bootstrapper" {
|
|
||||||
source = "./modules/load_balancer"
|
|
||||||
name = "${local.name}-bootstrapper"
|
|
||||||
vpc = aws_vpc.vpc.id
|
|
||||||
subnet = aws_subnet.main.id
|
|
||||||
port = local.ports_bootstrapper
|
|
||||||
}
|
|
||||||
|
|
||||||
module "load_balancer_kubernetes" {
|
|
||||||
source = "./modules/load_balancer"
|
|
||||||
name = "${local.name}-kubernetes"
|
|
||||||
vpc = aws_vpc.vpc.id
|
|
||||||
subnet = aws_subnet.main.id
|
|
||||||
port = local.ports_kubernetes
|
|
||||||
}
|
|
||||||
|
|
||||||
module "load_balancer_verify" {
|
|
||||||
source = "./modules/load_balancer"
|
|
||||||
name = "${local.name}-verify"
|
|
||||||
vpc = aws_vpc.vpc.id
|
|
||||||
subnet = aws_subnet.main.id
|
|
||||||
port = local.ports_verify
|
|
||||||
}
|
|
||||||
|
|
||||||
module "load_balancer_debugd" {
|
|
||||||
source = "./modules/load_balancer"
|
|
||||||
name = "${local.name}-debugd"
|
|
||||||
vpc = aws_vpc.vpc.id
|
|
||||||
subnet = aws_subnet.main.id
|
|
||||||
port = local.ports_debugd
|
|
||||||
}
|
|
||||||
|
|
||||||
module "load_balancer_konnectivity" {
|
|
||||||
source = "./modules/load_balancer"
|
|
||||||
name = "${local.name}-konnectivity"
|
|
||||||
vpc = aws_vpc.vpc.id
|
|
||||||
subnet = aws_subnet.main.id
|
|
||||||
port = local.ports_konnectivity
|
|
||||||
}
|
|
||||||
|
|
||||||
module "instance_group_control_plane" {
|
|
||||||
source = "./modules/instance_group"
|
|
||||||
name = local.name
|
|
||||||
role = "control-plane"
|
|
||||||
|
|
||||||
uid = local.uid
|
|
||||||
instance_type = var.instance_type
|
|
||||||
instance_count = var.count_control_plane
|
|
||||||
image_id = var.ami
|
|
||||||
disk_size = var.disk_size
|
|
||||||
target_group_arns = [
|
|
||||||
module.load_balancer_bootstrapper.target_group_arn,
|
|
||||||
module.load_balancer_kubernetes.target_group_arn,
|
|
||||||
module.load_balancer_verify.target_group_arn,
|
|
||||||
module.load_balancer_debugd.target_group_arn
|
|
||||||
]
|
|
||||||
subnetwork = aws_subnet.main.id
|
|
||||||
iam_instance_profile = var.control_plane_iam_instance_profile
|
|
||||||
}
|
|
||||||
|
|
||||||
module "instance_group_worker_nodes" {
|
|
||||||
source = "./modules/instance_group"
|
|
||||||
name = local.name
|
|
||||||
role = "worker"
|
|
||||||
uid = local.uid
|
|
||||||
instance_type = var.instance_type
|
|
||||||
instance_count = var.count_worker_nodes
|
|
||||||
image_id = var.ami
|
|
||||||
disk_size = var.disk_size
|
|
||||||
subnetwork = aws_subnet.main.id
|
|
||||||
target_group_arns = []
|
|
||||||
iam_instance_profile = var.worker_nodes_iam_instance_profile
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
variable "name" {
|
|
||||||
type = string
|
|
||||||
description = "Name of the load balancer."
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "port" {
|
|
||||||
type = string
|
|
||||||
description = "Port of the load balancer."
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "vpc" {
|
|
||||||
type = string
|
|
||||||
description = "ID of the VPC."
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "subnet" {
|
|
||||||
type = string
|
|
||||||
description = "ID of the subnets."
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
variable "name" {
|
|
||||||
type = string
|
|
||||||
description = "Name of your Constellation"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "worker_nodes_iam_instance_profile" {
|
|
||||||
type = string
|
|
||||||
description = "Name of the IAM instance profile for worker nodes"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "control_plane_iam_instance_profile" {
|
|
||||||
type = string
|
|
||||||
description = "Name of the IAM instance profile for control plane nodes"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "instance_type" {
|
|
||||||
type = string
|
|
||||||
description = "Instance type for worker nodes"
|
|
||||||
default = "t2.micro"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "disk_size" {
|
|
||||||
type = number
|
|
||||||
description = "Disk size for nodes [GB]"
|
|
||||||
default = 30
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "count_control_plane" {
|
|
||||||
type = number
|
|
||||||
description = "Number of control plane nodes"
|
|
||||||
default = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "count_worker_nodes" {
|
|
||||||
type = number
|
|
||||||
description = "Number of worker nodes"
|
|
||||||
default = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "ami" {
|
|
||||||
type = string
|
|
||||||
description = "AMI ID"
|
|
||||||
default = "ami-02f3416038bdb17fb" // Ubuntu 22.04 LTS
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "region" {
|
|
||||||
type = string
|
|
||||||
description = "AWS region"
|
|
||||||
default = "us-east-2"
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user