mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
Coordinator start: add skeleton to check for pre-existing node state
Signed-off-by: Malte Poll <mp@edgeless.systems>
This commit is contained in:
parent
462052427f
commit
bcd8c36777
@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/aws"
|
"github.com/edgelesssys/constellation/coordinator/attestation/aws"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/azure"
|
"github.com/edgelesssys/constellation/coordinator/attestation/azure"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/gcp"
|
"github.com/edgelesssys/constellation/coordinator/attestation/gcp"
|
||||||
@ -23,6 +24,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/coordinator/util"
|
"github.com/edgelesssys/constellation/coordinator/util"
|
||||||
"github.com/edgelesssys/constellation/coordinator/wireguard"
|
"github.com/edgelesssys/constellation/coordinator/wireguard"
|
||||||
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,6 +69,7 @@ func main() {
|
|||||||
var issuer core.QuoteIssuer
|
var issuer core.QuoteIssuer
|
||||||
var validator core.QuoteValidator
|
var validator core.QuoteValidator
|
||||||
var openTPM vtpm.TPMOpenFunc
|
var openTPM vtpm.TPMOpenFunc
|
||||||
|
var fs afero.Fs
|
||||||
|
|
||||||
switch strings.ToLower(os.Getenv(config.ConstellationCSP)) {
|
switch strings.ToLower(os.Getenv(config.ConstellationCSP)) {
|
||||||
case "aws":
|
case "aws":
|
||||||
@ -82,6 +85,7 @@ func main() {
|
|||||||
etcdEndpoint = defaultEtcdEndpoint
|
etcdEndpoint = defaultEtcdEndpoint
|
||||||
enforceEtcdTls = true
|
enforceEtcdTls = true
|
||||||
openTPM = vtpm.OpenNOPTPM
|
openTPM = vtpm.OpenNOPTPM
|
||||||
|
fs = afero.NewOsFs()
|
||||||
case "gcp":
|
case "gcp":
|
||||||
pcrs, err := vtpm.GetSelectedPCRs(vtpm.OpenVTPM, vtpm.GCPPCRSelection)
|
pcrs, err := vtpm.GetSelectedPCRs(vtpm.OpenVTPM, vtpm.GCPPCRSelection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -114,6 +118,7 @@ func main() {
|
|||||||
etcdEndpoint = defaultEtcdEndpoint
|
etcdEndpoint = defaultEtcdEndpoint
|
||||||
enforceEtcdTls = true
|
enforceEtcdTls = true
|
||||||
openTPM = vtpm.OpenVTPM
|
openTPM = vtpm.OpenVTPM
|
||||||
|
fs = afero.NewOsFs()
|
||||||
case "azure":
|
case "azure":
|
||||||
pcrs, err := vtpm.GetSelectedPCRs(vtpm.OpenVTPM, vtpm.AzurePCRSelection)
|
pcrs, err := vtpm.GetSelectedPCRs(vtpm.OpenVTPM, vtpm.AzurePCRSelection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -136,6 +141,7 @@ func main() {
|
|||||||
etcdEndpoint = defaultEtcdEndpoint
|
etcdEndpoint = defaultEtcdEndpoint
|
||||||
enforceEtcdTls = true
|
enforceEtcdTls = true
|
||||||
openTPM = vtpm.OpenVTPM
|
openTPM = vtpm.OpenVTPM
|
||||||
|
fs = afero.NewOsFs()
|
||||||
default:
|
default:
|
||||||
issuer = core.NewMockIssuer()
|
issuer = core.NewMockIssuer()
|
||||||
validator = core.NewMockValidator()
|
validator = core.NewMockValidator()
|
||||||
@ -148,10 +154,14 @@ func main() {
|
|||||||
bindPort = defaultPort
|
bindPort = defaultPort
|
||||||
etcdEndpoint = "etcd-storage:2379"
|
etcdEndpoint = "etcd-storage:2379"
|
||||||
enforceEtcdTls = false
|
enforceEtcdTls = false
|
||||||
openTPM = vtpm.OpenNOPTPM
|
var simulatedTPMCloser io.Closer
|
||||||
|
openTPM, simulatedTPMCloser = vtpm.NewSimulatedTPMOpenFunc()
|
||||||
|
defer simulatedTPMCloser.Close()
|
||||||
|
fs = afero.NewMemMapFs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileHandler := file.NewHandler(fs)
|
||||||
dialer := &net.Dialer{}
|
dialer := &net.Dialer{}
|
||||||
run(validator, issuer, wg, openTPM, util.GetIPAddr, dialer, kube,
|
run(validator, issuer, wg, openTPM, util.GetIPAddr, dialer, fileHandler, kube,
|
||||||
metadata, cloudControllerManager, cloudNodeManager, autoscaler, etcdEndpoint, enforceEtcdTls, bindIP, bindPort, zapLoggerCore)
|
metadata, cloudControllerManager, cloudNodeManager, autoscaler, etcdEndpoint, enforceEtcdTls, bindIP, bindPort, zapLoggerCore)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/coordinator/core"
|
"github.com/edgelesssys/constellation/coordinator/core"
|
||||||
@ -25,7 +26,7 @@ import (
|
|||||||
|
|
||||||
var version = "0.0.0"
|
var version = "0.0.0"
|
||||||
|
|
||||||
func run(validator core.QuoteValidator, issuer core.QuoteIssuer, vpn core.VPN, openTPM vtpm.TPMOpenFunc, getPublicIPAddr func() (string, error), dialer pubapi.Dialer,
|
func run(validator core.QuoteValidator, issuer core.QuoteIssuer, vpn core.VPN, openTPM vtpm.TPMOpenFunc, getPublicIPAddr func() (string, error), dialer pubapi.Dialer, fileHandler file.Handler,
|
||||||
kube core.Cluster, metadata core.ProviderMetadata, cloudControllerManager core.CloudControllerManager, cloudNodeManager core.CloudNodeManager, clusterAutoscaler core.ClusterAutoscaler, etcdEndpoint string, etcdTLS bool, bindIP, bindPort string, zapLoggerCore *zap.Logger,
|
kube core.Cluster, metadata core.ProviderMetadata, cloudControllerManager core.CloudControllerManager, cloudNodeManager core.CloudNodeManager, clusterAutoscaler core.ClusterAutoscaler, etcdEndpoint string, etcdTLS bool, bindIP, bindPort string, zapLoggerCore *zap.Logger,
|
||||||
) {
|
) {
|
||||||
defer zapLoggerCore.Sync()
|
defer zapLoggerCore.Sync()
|
||||||
@ -41,10 +42,16 @@ func run(validator core.QuoteValidator, issuer core.QuoteIssuer, vpn core.VPN, o
|
|||||||
ForceTLS: etcdTLS,
|
ForceTLS: etcdTLS,
|
||||||
Logger: zapLoggerCore.WithOptions(zap.IncreaseLevel(zap.WarnLevel)).Named("etcd"),
|
Logger: zapLoggerCore.WithOptions(zap.IncreaseLevel(zap.WarnLevel)).Named("etcd"),
|
||||||
}
|
}
|
||||||
core, err := core.NewCore(vpn, kube, metadata, cloudControllerManager, cloudNodeManager, clusterAutoscaler, zapLoggerCore, openTPM, etcdStoreFactory)
|
core, err := core.NewCore(vpn, kube, metadata, cloudControllerManager, cloudNodeManager, clusterAutoscaler, zapLoggerCore, openTPM, etcdStoreFactory, fileHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zapLoggerCore.Fatal("failed to create core", zap.Error(err))
|
zapLoggerCore.Fatal("failed to create core", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
// initialize state machine and wait for re-joining of the VPN (if applicable)
|
||||||
|
nodeActivated, err := core.Initialize()
|
||||||
|
if err != nil {
|
||||||
|
zapLoggerCore.Fatal("failed to initialize core", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
vapiServer := &vpnAPIServer{logger: zapLoggerCore.Named("vpnapi"), core: core}
|
vapiServer := &vpnAPIServer{logger: zapLoggerCore.Named("vpnapi"), core: core}
|
||||||
zapLoggerPubapi := zapLoggerCore.Named("pubapi")
|
zapLoggerPubapi := zapLoggerCore.Named("pubapi")
|
||||||
papi := pubapi.New(zapLoggerPubapi, core, dialer, vapiServer, validator, getPublicIPAddr)
|
papi := pubapi.New(zapLoggerPubapi, core, dialer, vapiServer, validator, getPublicIPAddr)
|
||||||
@ -80,9 +87,11 @@ func run(validator core.QuoteValidator, issuer core.QuoteIssuer, vpn core.VPN, o
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
zapLoggerStartupJoin := zapLoggerCore.Named("startup-join")
|
if !nodeActivated {
|
||||||
if err := tryJoinClusterOnStartup(getPublicIPAddr, metadata, bindPort, zapLoggerStartupJoin); err != nil {
|
zapLoggerStartupJoin := zapLoggerCore.Named("startup-join")
|
||||||
zapLoggerStartupJoin.Info("joining existing cluster on startup failed. Waiting for connection.", zap.Error(err))
|
if err := tryJoinClusterOnStartup(getPublicIPAddr, metadata, bindPort, zapLoggerStartupJoin); err != nil {
|
||||||
|
zapLoggerStartupJoin.Info("joining existing cluster on startup failed. Waiting for connection.", zap.Error(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/coordinator/core"
|
"github.com/edgelesssys/constellation/coordinator/core"
|
||||||
@ -15,10 +16,12 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/coordinator/peer"
|
"github.com/edgelesssys/constellation/coordinator/peer"
|
||||||
"github.com/edgelesssys/constellation/coordinator/pubapi"
|
"github.com/edgelesssys/constellation/coordinator/pubapi"
|
||||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||||
|
"github.com/edgelesssys/constellation/coordinator/state"
|
||||||
"github.com/edgelesssys/constellation/coordinator/store"
|
"github.com/edgelesssys/constellation/coordinator/store"
|
||||||
"github.com/edgelesssys/constellation/coordinator/util/testdialer"
|
"github.com/edgelesssys/constellation/coordinator/util/testdialer"
|
||||||
"github.com/edgelesssys/constellation/coordinator/vpnapi"
|
"github.com/edgelesssys/constellation/coordinator/vpnapi"
|
||||||
"github.com/edgelesssys/constellation/coordinator/vpnapi/vpnproto"
|
"github.com/edgelesssys/constellation/coordinator/vpnapi/vpnproto"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/goleak"
|
"go.uber.org/goleak"
|
||||||
@ -189,8 +192,9 @@ func TestConcurrent(t *testing.T) {
|
|||||||
|
|
||||||
func spawnPeer(require *require.Assertions, logger *zap.Logger, dialer *testdialer.BufconnDialer, netw *network, endpoint string) (*grpc.Server, *pubapi.API, *fakeVPN) {
|
func spawnPeer(require *require.Assertions, logger *zap.Logger, dialer *testdialer.BufconnDialer, netw *network, endpoint string) (*grpc.Server, *pubapi.API, *fakeVPN) {
|
||||||
vpn := newVPN(netw, endpoint)
|
vpn := newVPN(netw, endpoint)
|
||||||
cor, err := core.NewCore(vpn, &core.ClusterFake{}, &core.ProviderMetadataFake{}, &core.CloudControllerManagerFake{}, &core.CloudNodeManagerFake{}, &core.ClusterAutoscalerFake{}, logger, vtpm.OpenSimulatedTPM, fakeStoreFactory{})
|
cor, err := core.NewCore(vpn, &core.ClusterFake{}, &core.ProviderMetadataFake{}, &core.CloudControllerManagerFake{}, &core.CloudNodeManagerFake{}, &core.ClusterAutoscalerFake{}, logger, vtpm.OpenSimulatedTPM, fakeStoreFactory{}, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
require.NoError(cor.AdvanceState(state.AcceptingInit, nil, nil))
|
||||||
|
|
||||||
getPublicAddr := func() (string, error) {
|
getPublicAddr := func() (string, error) {
|
||||||
return "192.0.2.1", nil
|
return "192.0.2.1", nil
|
||||||
|
@ -5,9 +5,11 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/coordinator/kubernetes"
|
"github.com/edgelesssys/constellation/coordinator/kubernetes"
|
||||||
"github.com/edgelesssys/constellation/coordinator/kubernetes/k8sapi/resources"
|
"github.com/edgelesssys/constellation/coordinator/kubernetes/k8sapi/resources"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -167,7 +169,7 @@ func TestInitCluster(t *testing.T) {
|
|||||||
|
|
||||||
zapLogger, err := zap.NewDevelopment()
|
zapLogger, err := zap.NewDevelopment()
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
core, err := NewCore(&stubVPN{}, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, zapLogger, vtpm.OpenSimulatedTPM, nil)
|
core, err := NewCore(&stubVPN{}, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, zapLogger, vtpm.OpenSimulatedTPM, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
kubeconfig, err := core.InitCluster(tc.autoscalingNodeGroups, "cloud-service-account-uri")
|
kubeconfig, err := core.InitCluster(tc.autoscalingNodeGroups, "cloud-service-account-uri")
|
||||||
@ -282,7 +284,7 @@ func TestJoinCluster(t *testing.T) {
|
|||||||
|
|
||||||
zapLogger, err := zap.NewDevelopment()
|
zapLogger, err := zap.NewDevelopment()
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
core, err := NewCore(&tc.vpn, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, zapLogger, vtpm.OpenSimulatedTPM, nil)
|
core, err := NewCore(&tc.vpn, &tc.cluster, &tc.metadata, &tc.cloudControllerManager, &tc.cloudNodeManager, &tc.clusterAutoscaler, zapLogger, vtpm.OpenSimulatedTPM, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
joinReq := kubeadm.BootstrapTokenDiscovery{
|
joinReq := kubeadm.BootstrapTokenDiscovery{
|
||||||
|
@ -3,14 +3,18 @@ package core
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/coordinator/config"
|
"github.com/edgelesssys/constellation/coordinator/config"
|
||||||
kmsSetup "github.com/edgelesssys/constellation/coordinator/kms"
|
kmsSetup "github.com/edgelesssys/constellation/coordinator/kms"
|
||||||
|
"github.com/edgelesssys/constellation/coordinator/nodestate"
|
||||||
|
"github.com/edgelesssys/constellation/coordinator/role"
|
||||||
"github.com/edgelesssys/constellation/coordinator/state"
|
"github.com/edgelesssys/constellation/coordinator/state"
|
||||||
"github.com/edgelesssys/constellation/coordinator/store"
|
"github.com/edgelesssys/constellation/coordinator/store"
|
||||||
"github.com/edgelesssys/constellation/coordinator/storewrapper"
|
"github.com/edgelesssys/constellation/coordinator/storewrapper"
|
||||||
@ -36,12 +40,13 @@ type Core struct {
|
|||||||
zaplogger *zap.Logger
|
zaplogger *zap.Logger
|
||||||
persistentStoreFactory PersistentStoreFactory
|
persistentStoreFactory PersistentStoreFactory
|
||||||
lastHeartbeats map[string]time.Time
|
lastHeartbeats map[string]time.Time
|
||||||
|
fileHandler file.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCore creates and initializes a new Core object.
|
// NewCore creates and initializes a new Core object.
|
||||||
func NewCore(vpn VPN, kube Cluster,
|
func NewCore(vpn VPN, kube Cluster,
|
||||||
metadata ProviderMetadata, cloudControllerManager CloudControllerManager, cloudNodeManager CloudNodeManager, clusterAutoscaler ClusterAutoscaler,
|
metadata ProviderMetadata, cloudControllerManager CloudControllerManager, cloudNodeManager CloudNodeManager, clusterAutoscaler ClusterAutoscaler,
|
||||||
zapLogger *zap.Logger, openTPM vtpm.TPMOpenFunc, persistentStoreFactory PersistentStoreFactory,
|
zapLogger *zap.Logger, openTPM vtpm.TPMOpenFunc, persistentStoreFactory PersistentStoreFactory, fileHandler file.Handler,
|
||||||
) (*Core, error) {
|
) (*Core, error) {
|
||||||
stor := store.NewStdStore()
|
stor := store.NewStdStore()
|
||||||
c := &Core{
|
c := &Core{
|
||||||
@ -57,6 +62,7 @@ func NewCore(vpn VPN, kube Cluster,
|
|||||||
kms: nil, // KMS is set up during init phase
|
kms: nil, // KMS is set up during init phase
|
||||||
persistentStoreFactory: persistentStoreFactory,
|
persistentStoreFactory: persistentStoreFactory,
|
||||||
lastHeartbeats: make(map[string]time.Time),
|
lastHeartbeats: make(map[string]time.Time),
|
||||||
|
fileHandler: fileHandler,
|
||||||
}
|
}
|
||||||
if err := c.data().IncrementPeersResourceVersion(); err != nil {
|
if err := c.data().IncrementPeersResourceVersion(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -76,8 +82,6 @@ func NewCore(vpn VPN, kube Cluster,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.state.Advance(state.AcceptingInit)
|
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +187,49 @@ func (c *Core) NotifyNodeHeartbeat(addr net.Addr) {
|
|||||||
c.mut.Unlock()
|
c.mut.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize initializes the state machine of the core and handles re-joining the VPN.
|
||||||
|
// Blocks until the core is ready to be used.
|
||||||
|
func (c *Core) Initialize() (nodeActivated bool, err error) {
|
||||||
|
nodeActivated, err = vtpm.IsNodeInitialized(c.openTPM)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to check for previous activation using vTPM: %w", err)
|
||||||
|
}
|
||||||
|
if !nodeActivated {
|
||||||
|
c.zaplogger.Info("Node was never activated. Allowing node to be activated.")
|
||||||
|
c.state.Advance(state.AcceptingInit)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
c.zaplogger.Info("Node was previously activated. Attempting re-join.")
|
||||||
|
nodeState, err := nodestate.FromFile(c.fileHandler)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to read node state: %w", err)
|
||||||
|
}
|
||||||
|
var initialState state.State
|
||||||
|
switch nodeState.Role {
|
||||||
|
case role.Coordinator:
|
||||||
|
initialState = state.ActivatingNodes
|
||||||
|
case role.Node:
|
||||||
|
initialState = state.IsNode
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf("invalid node role for initialized node: %v", nodeState.Role)
|
||||||
|
}
|
||||||
|
// TODO: if node was previously initialized, attempt to re-join wireguard here.
|
||||||
|
// Steps to rejoining should include:
|
||||||
|
// - retrieve list of coordinators from cloud provider API
|
||||||
|
// - attempt to retrieve list of wireguard public keys from any other coordinator while checking for correct PCRs in ATLS
|
||||||
|
// - re-establish wireguard connections
|
||||||
|
// - call update function successfully at least once
|
||||||
|
// - advance state to IsNode or ActivatingNodes respectively
|
||||||
|
// - restart update loop
|
||||||
|
// This procedure can be retried until it succeeds.
|
||||||
|
// The node must be put into the correct state before the update loop is started.
|
||||||
|
panic("not implemented")
|
||||||
|
|
||||||
|
//nolint:govet // this code is unreachable as long as the above is unimplemented
|
||||||
|
c.state.Advance(initialState)
|
||||||
|
return nodeActivated, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetUpKMS sets the Coordinators key management service and key encryption key ID.
|
// SetUpKMS sets the Coordinators key management service and key encryption key ID.
|
||||||
// Creates a new key encryption key in the KMS, if requested.
|
// Creates a new key encryption key in the KMS, if requested.
|
||||||
// Otherwise the KEK is assumed to already exist in the KMS.
|
// Otherwise the KEK is assumed to already exist in the KMS.
|
||||||
|
@ -6,8 +6,14 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
|
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||||
|
"github.com/edgelesssys/constellation/coordinator/nodestate"
|
||||||
|
"github.com/edgelesssys/constellation/coordinator/role"
|
||||||
|
"github.com/edgelesssys/constellation/coordinator/state"
|
||||||
"github.com/edgelesssys/constellation/coordinator/store"
|
"github.com/edgelesssys/constellation/coordinator/store"
|
||||||
"github.com/edgelesssys/constellation/coordinator/storewrapper"
|
"github.com/edgelesssys/constellation/coordinator/storewrapper"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/goleak"
|
"go.uber.org/goleak"
|
||||||
@ -28,7 +34,7 @@ func TestAddAdmin(t *testing.T) {
|
|||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
vpn := &stubVPN{}
|
vpn := &stubVPN{}
|
||||||
core, err := NewCore(vpn, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil)
|
core, err := NewCore(vpn, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
require.NoError(core.InitializeStoreIPs())
|
require.NoError(core.InitializeStoreIPs())
|
||||||
|
|
||||||
@ -44,7 +50,7 @@ func TestGetNextNodeIP(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil)
|
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
require.NoError(core.InitializeStoreIPs())
|
require.NoError(core.InitializeStoreIPs())
|
||||||
|
|
||||||
@ -87,7 +93,7 @@ func TestSwitchToPersistentStore(t *testing.T) {
|
|||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
storeFactory := &fakeStoreFactory{}
|
storeFactory := &fakeStoreFactory{}
|
||||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, storeFactory)
|
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, storeFactory, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
require.NoError(core.SwitchToPersistentStore())
|
require.NoError(core.SwitchToPersistentStore())
|
||||||
@ -101,7 +107,7 @@ func TestGetIDs(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil)
|
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
_, _, err = core.GetIDs(nil)
|
_, _, err = core.GetIDs(nil)
|
||||||
@ -125,7 +131,7 @@ func TestNotifyNodeHeartbeat(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil)
|
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
const ip = "192.0.2.1"
|
const ip = "192.0.2.1"
|
||||||
@ -138,7 +144,7 @@ func TestDeriveKey(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil)
|
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
// error when no kms is set up
|
// error when no kms is set up
|
||||||
@ -165,6 +171,80 @@ func TestDeriveKey(t *testing.T) {
|
|||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInitialize(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
initializePCRs bool
|
||||||
|
writeNodeState bool
|
||||||
|
role role.Role
|
||||||
|
expectActivated bool
|
||||||
|
expectedState state.State
|
||||||
|
expectPanic bool
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
"fresh node": {
|
||||||
|
expectedState: state.AcceptingInit,
|
||||||
|
},
|
||||||
|
"activated coordinator": {
|
||||||
|
initializePCRs: true,
|
||||||
|
writeNodeState: true,
|
||||||
|
role: role.Coordinator,
|
||||||
|
expectPanic: true, // TODO: adapt test case once restart is implemented
|
||||||
|
expectActivated: true,
|
||||||
|
expectedState: state.ActivatingNodes,
|
||||||
|
},
|
||||||
|
"activated node": {
|
||||||
|
initializePCRs: true,
|
||||||
|
writeNodeState: true,
|
||||||
|
role: role.Node,
|
||||||
|
expectPanic: true, // TODO: adapt test case once restart is implemented
|
||||||
|
expectActivated: true,
|
||||||
|
expectedState: state.IsNode,
|
||||||
|
},
|
||||||
|
"activated node with no node state": {
|
||||||
|
initializePCRs: true,
|
||||||
|
writeNodeState: false,
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
openTPM, simulatedTPMCloser := vtpm.NewSimulatedTPMOpenFunc()
|
||||||
|
defer simulatedTPMCloser.Close()
|
||||||
|
if tc.initializePCRs {
|
||||||
|
require.NoError(vtpm.MarkNodeAsInitialized(openTPM, []byte{0x0, 0x1, 0x2, 0x3}, []byte{0x4, 0x5, 0x6, 0x7}))
|
||||||
|
}
|
||||||
|
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
||||||
|
if tc.writeNodeState {
|
||||||
|
require.NoError((&nodestate.NodeState{
|
||||||
|
Role: tc.role,
|
||||||
|
VPNPrivKey: []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7},
|
||||||
|
}).ToFile(fileHandler))
|
||||||
|
}
|
||||||
|
|
||||||
|
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), openTPM, nil, fileHandler)
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
if tc.expectPanic {
|
||||||
|
assert.Panics(func() { _, _ = core.Initialize() })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeActivated, err := core.Initialize()
|
||||||
|
if tc.expectErr {
|
||||||
|
assert.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(err)
|
||||||
|
assert.Equal(tc.expectActivated, nodeActivated)
|
||||||
|
assert.Equal(tc.expectedState, core.state)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type fakeStoreFactory struct {
|
type fakeStoreFactory struct {
|
||||||
store store.Store
|
store store.Store
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,16 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
"github.com/edgelesssys/constellation/coordinator/atls"
|
"github.com/edgelesssys/constellation/coordinator/atls"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/coordinator/kms"
|
"github.com/edgelesssys/constellation/coordinator/kms"
|
||||||
"github.com/edgelesssys/constellation/coordinator/pubapi"
|
"github.com/edgelesssys/constellation/coordinator/pubapi"
|
||||||
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
"github.com/edgelesssys/constellation/coordinator/pubapi/pubproto"
|
||||||
|
"github.com/edgelesssys/constellation/coordinator/state"
|
||||||
"github.com/edgelesssys/constellation/coordinator/vpnapi"
|
"github.com/edgelesssys/constellation/coordinator/vpnapi"
|
||||||
"github.com/edgelesssys/constellation/coordinator/vpnapi/vpnproto"
|
"github.com/edgelesssys/constellation/coordinator/vpnapi/vpnproto"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -145,10 +148,13 @@ func newMockCoreWithDialer(dialer *bufconnDialer) (*Core, *pubapi.API, error) {
|
|||||||
getPublicAddr := func() (string, error) {
|
getPublicAddr := func() (string, error) {
|
||||||
return "192.0.2.1", nil
|
return "192.0.2.1", nil
|
||||||
}
|
}
|
||||||
core, err := NewCore(vpn, kubeFake, metadataFake, ccmFake, cnmFake, autoscalerFake, zapLogger, vtpm.OpenSimulatedTPM, &fakeStoreFactory{})
|
core, err := NewCore(vpn, kubeFake, metadataFake, ccmFake, cnmFake, autoscalerFake, zapLogger, vtpm.OpenSimulatedTPM, &fakeStoreFactory{}, file.NewHandler(afero.NewMemMapFs()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
if err := core.AdvanceState(state.AcceptingInit, nil, nil); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
vapiServer := &fakeVPNAPIServer{logger: zapLogger, core: core, dialer: dialer}
|
vapiServer := &fakeVPNAPIServer{logger: zapLogger, core: core, dialer: dialer}
|
||||||
papi := pubapi.New(zapLogger, core, dialer, vapiServer, validator, getPublicAddr)
|
papi := pubapi.New(zapLogger, core, dialer, vapiServer, validator, getPublicAddr)
|
||||||
|
@ -4,7 +4,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
"github.com/edgelesssys/constellation/coordinator/peer"
|
"github.com/edgelesssys/constellation/coordinator/peer"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap/zaptest"
|
"go.uber.org/zap/zaptest"
|
||||||
@ -51,7 +53,7 @@ func TestGetPeers(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil)
|
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
// prepare store
|
// prepare store
|
||||||
@ -119,7 +121,7 @@ func TestAddPeer(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
core, err := NewCore(&tc.vpn, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil)
|
core, err := NewCore(&tc.vpn, nil, nil, nil, nil, nil, zaptest.NewLogger(t), nil, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
err = core.AddPeer(tc.peer)
|
err = core.AddPeer(tc.peer)
|
||||||
|
@ -5,8 +5,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/cli/file"
|
||||||
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
"github.com/edgelesssys/constellation/coordinator/attestation/vtpm"
|
||||||
"github.com/edgelesssys/constellation/coordinator/state"
|
"github.com/edgelesssys/constellation/coordinator/state"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap/zaptest"
|
"go.uber.org/zap/zaptest"
|
||||||
@ -63,9 +65,9 @@ func TestAdvanceState(t *testing.T) {
|
|||||||
return vtpm.OpenSimulatedTPM()
|
return vtpm.OpenSimulatedTPM()
|
||||||
}
|
}
|
||||||
|
|
||||||
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), openTPM, nil)
|
core, err := NewCore(&stubVPN{}, nil, nil, nil, nil, nil, zaptest.NewLogger(t), openTPM, nil, file.NewHandler(afero.NewMemMapFs()))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
assert.Equal(state.AcceptingInit, core.GetState())
|
assert.Equal(state.Uninitialized, core.GetState())
|
||||||
core.state = tc.initialState
|
core.state = tc.initialState
|
||||||
|
|
||||||
err = core.AdvanceState(tc.newState, []byte("secret"), []byte("cluster"))
|
err = core.AdvanceState(tc.newState, []byte("secret"), []byte("cluster"))
|
||||||
|
Loading…
Reference in New Issue
Block a user