mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
dev-docs: Go package docs (#958)
* Remove unused package * Add Go package docs to most packages Signed-off-by: Daniel Weiße <dw@edgeless.systems> Signed-off-by: Fabian Kammel <fk@edgeless.systems> Signed-off-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> Co-authored-by: Fabian Kammel <fk@edgeless.systems>
This commit is contained in:
parent
b7740723ac
commit
690b50b29d
@ -9,7 +9,7 @@ The bootstrapper has two active components:
|
|||||||
|
|
||||||
## Init Flow
|
## Init Flow
|
||||||
|
|
||||||
The InitServer is a gRPC server that is listining for initialization requests.
|
The InitServer is a gRPC server that is listening for initialization requests.
|
||||||
The first instance needs to be initialized by the user, see the [initproto](./initproto)
|
The first instance needs to be initialized by the user, see the [initproto](./initproto)
|
||||||
for a description of the initialization protocol. The client that talks to this server
|
for a description of the initialization protocol. The client that talks to this server
|
||||||
is part of Constellation's CLI.
|
is part of Constellation's CLI.
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/helm"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/helm"
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes"
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi"
|
||||||
kubewaiter "github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/kubeWaiter"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/kubewaiter"
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/logging"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/logging"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/atls"
|
"github.com/edgelesssys/constellation/v2/internal/atls"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/aws"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/aws"
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package certificate provides functions to create a certificate request and matching private key.
|
||||||
package certificate
|
package certificate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -11,9 +12,32 @@ import (
|
|||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CertificateFilename is the path to the kubelets certificate.
|
||||||
|
CertificateFilename = "/run/state/kubelet/pki/kubelet-client-crt.pem"
|
||||||
|
// KeyFilename is the path to the kubelets private key.
|
||||||
|
KeyFilename = "/run/state/kubelet/pki/kubelet-client-key.pem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetKubeletCertificateRequest returns a certificate request and matching private key for the kubelet.
|
||||||
|
func GetKubeletCertificateRequest(nodeName string, ips []net.IP) (certificateRequest []byte, privateKey []byte, err error) {
|
||||||
|
csrTemplate := &x509.CertificateRequest{
|
||||||
|
Subject: pkix.Name{
|
||||||
|
Organization: []string{constants.NodesGroup},
|
||||||
|
CommonName: constants.NodesUserPrefix + nodeName,
|
||||||
|
},
|
||||||
|
IPAddresses: ips,
|
||||||
|
}
|
||||||
|
return GetCertificateRequest(csrTemplate)
|
||||||
|
}
|
||||||
|
|
||||||
// GetCertificateRequest returns a certificate request and matching private key.
|
// GetCertificateRequest returns a certificate request and matching private key.
|
||||||
func GetCertificateRequest(csrTemplate *x509.CertificateRequest) (certificateRequest []byte, privateKey []byte, err error) {
|
func GetCertificateRequest(csrTemplate *x509.CertificateRequest) (certificateRequest []byte, privateKey []byte, err error) {
|
||||||
privK, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
privK, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package clean provides functionality to stop a list of services gracefully and synchronously.
|
||||||
package clean
|
package clean
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,12 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package diskencryption handles interaction with a node's state disk.
|
||||||
|
|
||||||
|
This package is not thread safe, since libcryptsetup is not thread safe.
|
||||||
|
There should only be one instance using this package per process.
|
||||||
|
*/
|
||||||
package diskencryption
|
package diskencryption
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package helm is used to install Constellation microservices and other services during cluster initialization.
|
||||||
package helm
|
package helm
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,17 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# InitServer
|
||||||
|
|
||||||
|
The InitServer is one of the two main components of the bootstrapper.
|
||||||
|
It is responsible for the initial setup of a node, and the initialization of the Kubernetes cluster.
|
||||||
|
|
||||||
|
The InitServer is started on each node, and waits for either a call from the CLI,
|
||||||
|
or for the JoinClient to connect to an existing cluster.
|
||||||
|
|
||||||
|
If a call from the CLI is received, the InitServer bootstraps the Kubernetes cluster, and stops the JoinClient.
|
||||||
|
*/
|
||||||
package initserver
|
package initserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,17 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# JoinClient
|
||||||
|
|
||||||
|
The JoinClient is one of the two main components of the bootstrapper.
|
||||||
|
It is responsible for for the initial setup of a node, and joining an existing Kubernetes cluster.
|
||||||
|
|
||||||
|
The JoinClient is started on each node, it then continuously checks for an existing cluster to join,
|
||||||
|
or for the InitServer to bootstrap a new cluster.
|
||||||
|
|
||||||
|
If the JoinClient finds an existing cluster, it will attempt to join it as either a control-plane or a worker node.
|
||||||
|
*/
|
||||||
package joinclient
|
package joinclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -16,8 +27,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/certificate"
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/diskencryption"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/diskencryption"
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubelet"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
"github.com/edgelesssys/constellation/v2/internal/attestation"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/metadata"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/metadata"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
@ -201,7 +212,7 @@ func (c *JoinClient) join(serviceEndpoint string) error {
|
|||||||
ctx, cancel := c.timeoutCtx()
|
ctx, cancel := c.timeoutCtx()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
certificateRequest, kubeletKey, err := kubelet.GetCertificateRequest(c.nodeName, c.validIPs)
|
certificateRequest, kubeletKey, err := certificate.GetKubeletCertificateRequest(c.nodeName, c.validIPs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -267,10 +278,10 @@ func (c *JoinClient) startNodeAndJoin(ticket *joinproto.IssueJoinTicketResponse,
|
|||||||
return fmt.Errorf("writing control plane files: %w", err)
|
return fmt.Errorf("writing control plane files: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := c.fileHandler.Write(kubelet.CertificateFilename, ticket.KubeletCert, file.OptMkdirAll); err != nil {
|
if err := c.fileHandler.Write(certificate.CertificateFilename, ticket.KubeletCert, file.OptMkdirAll); err != nil {
|
||||||
return fmt.Errorf("writing kubelet certificate: %w", err)
|
return fmt.Errorf("writing kubelet certificate: %w", err)
|
||||||
}
|
}
|
||||||
if err := c.fileHandler.Write(kubelet.KeyFilename, kubeletKey, file.OptMkdirAll); err != nil {
|
if err := c.fileHandler.Write(certificate.KeyFilename, kubeletKey, file.OptMkdirAll); err != nil {
|
||||||
return fmt.Errorf("writing kubelet key: %w", err)
|
return fmt.Errorf("writing kubelet key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) Edgeless Systems GmbH
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package kubelet
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/x509"
|
|
||||||
"crypto/x509/pkix"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/certificate"
|
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// CertificateFilename is the path to the kubelets certificate.
|
|
||||||
CertificateFilename = "/run/state/kubelet/pki/kubelet-client-crt.pem"
|
|
||||||
// KeyFilename is the path to the kubelets private key.
|
|
||||||
KeyFilename = "/run/state/kubelet/pki/kubelet-client-key.pem"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetCertificateRequest returns a certificate request and macthing private key for the kubelet.
|
|
||||||
func GetCertificateRequest(nodeName string, ips []net.IP) (certificateRequest []byte, privateKey []byte, err error) {
|
|
||||||
csrTemplate := &x509.CertificateRequest{
|
|
||||||
Subject: pkix.Name{
|
|
||||||
Organization: []string{constants.NodesGroup},
|
|
||||||
CommonName: constants.NodesUserPrefix + nodeName,
|
|
||||||
},
|
|
||||||
IPAddresses: ips,
|
|
||||||
}
|
|
||||||
return certificate.GetCertificateRequest(csrTemplate)
|
|
||||||
}
|
|
8
bootstrapper/internal/kubernetes/k8sapi/k8sapi.go
Normal file
8
bootstrapper/internal/kubernetes/k8sapi/k8sapi.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package k8sapi is used to interact with the Kubernetes API to create or update required resources.
|
||||||
|
package k8sapi
|
@ -22,7 +22,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubelet"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/certificate"
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi/resources"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi/resources"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/role"
|
"github.com/edgelesssys/constellation/v2/internal/role"
|
||||||
@ -345,11 +345,11 @@ func (k *KubernetesUtil) StartKubelet() error {
|
|||||||
// This is necessary because this node does not request a certificate from the join service.
|
// This is necessary because this node does not request a certificate from the join service.
|
||||||
func (k *KubernetesUtil) createSignedKubeletCert(nodeName string, ips []net.IP) error {
|
func (k *KubernetesUtil) createSignedKubeletCert(nodeName string, ips []net.IP) error {
|
||||||
// Create CSR
|
// Create CSR
|
||||||
certRequestRaw, kubeletKey, err := kubelet.GetCertificateRequest(nodeName, ips)
|
certRequestRaw, kubeletKey, err := certificate.GetKubeletCertificateRequest(nodeName, ips)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := k.file.Write(kubelet.KeyFilename, kubeletKey, file.OptMkdirAll); err != nil {
|
if err := k.file.Write(certificate.KeyFilename, kubeletKey, file.OptMkdirAll); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +399,7 @@ func (k *KubernetesUtil) createSignedKubeletCert(nodeName string, ips []net.IP)
|
|||||||
Bytes: certRaw,
|
Bytes: certRaw,
|
||||||
})
|
})
|
||||||
|
|
||||||
return k.file.Write(kubelet.CertificateFilename, kubeletCert, file.OptMkdirAll)
|
return k.file.Write(certificate.CertificateFilename, kubeletCert, file.OptMkdirAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createSignedKonnectivityCert manually creates a Kubernetes CA signed certificate for the Konnectivity server.
|
// createSignedKonnectivityCert manually creates a Kubernetes CA signed certificate for the Konnectivity server.
|
||||||
|
@ -9,7 +9,7 @@ package k8sapi
|
|||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubelet"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/certificate"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/kubernetes"
|
"github.com/edgelesssys/constellation/v2/internal/kubernetes"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
@ -166,8 +166,8 @@ func (c *KubdeadmConfiguration) InitConfiguration(externalCloudProvider bool, cl
|
|||||||
Effect: corev1.TaintEffectPreferNoSchedule,
|
Effect: corev1.TaintEffectPreferNoSchedule,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TLSCertFile: kubelet.CertificateFilename,
|
TLSCertFile: certificate.CertificateFilename,
|
||||||
TLSPrivateKeyFile: kubelet.KeyFilename,
|
TLSPrivateKeyFile: certificate.KeyFilename,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package resources contains Kubernetes configs and policies for Constellation.
|
||||||
|
package resources
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package kubernetes provides functionality to bootstrap a Kubernetes cluster, or join an exiting one.
|
||||||
package kubernetes
|
package kubernetes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -19,7 +20,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi"
|
||||||
kubewaiter "github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/kubeWaiter"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/kubewaiter"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/azureshared"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/azureshared"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/k8sapi"
|
||||||
kubewaiter "github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/kubeWaiter"
|
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/kubernetes/kubewaiter"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/metadata"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/metadata"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
|
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package kubewaiter is used to wait for the Kubernetes API to be available.
|
||||||
package kubewaiter
|
package kubewaiter
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package logging provides an interface for logging information to a non-confidential destination
|
||||||
package logging
|
package logging
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package nodelock handles locking operations on the node.
|
||||||
package nodelock
|
package nodelock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,11 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package cmd is the entrypoint of the Constellation CLI.
|
||||||
|
|
||||||
|
Business logic of the CLI shall be implemented in the internal/cmd package.
|
||||||
|
*/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
22
cli/internal/cloudcmd/cloudcmd.go
Normal file
22
cli/internal/cloudcmd/cloudcmd.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package cloudcmd provides executable command for the CLI.
|
||||||
|
|
||||||
|
This package focuses on the interaction with the cloud provider.
|
||||||
|
It separates the cloud provider specific code from the rest of the CLI, and
|
||||||
|
provides a common interface for all cloud providers.
|
||||||
|
|
||||||
|
Exported functions must not be cloud provider specific, but rather take a
|
||||||
|
cloudprovider.Provider as an argument.
|
||||||
|
|
||||||
|
User interaction happens in the cmd package, and should not happen or pass through
|
||||||
|
this package.
|
||||||
|
|
||||||
|
The backend to this package is currently provided by the terraform package.
|
||||||
|
*/
|
||||||
|
package cloudcmd
|
12
cli/internal/cmd/cmd.go
Normal file
12
cli/internal/cmd/cmd.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package cmd provides the Constellation CLI.
|
||||||
|
|
||||||
|
It is responsible for the interaction with the user.
|
||||||
|
*/
|
||||||
|
package cmd
|
@ -4,6 +4,11 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package image provides helping wrappers around a versionsapi fetcher.
|
||||||
|
|
||||||
|
It also enables local image overrides and download of raw images.
|
||||||
|
*/
|
||||||
package image
|
package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package libvirt is used to start and stop containerized libvirt instances.
|
||||||
package libvirt
|
package libvirt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,14 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package terraform handles creation/destruction of a Constellation cluster using Terraform.
|
||||||
|
|
||||||
|
Since Terraform does not provide a stable Go API, we use the `terraform-exec` package to interact with Terraform.
|
||||||
|
|
||||||
|
The Terraform templates are located in the "terraform" subdirectory. The templates are embedded into the CLI binary using `go:embed`.
|
||||||
|
On use the relevant template is extracted to the working directory and the user customized variables are written to a `terraform.tfvars` file.
|
||||||
|
*/
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package cryptmapper provides a wrapper around libcryptsetup to manage dm-crypt volumes for CSI drivers.
|
||||||
package cryptmapper
|
package cryptmapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -141,6 +141,26 @@ the `<REPOSITORY>/.vscode/settings.json` repo, so the settings will only affect
|
|||||||
|
|
||||||
Additionally, we use the [Redhat YAML formatter](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) to have uniform formatting in our `.yaml` files.
|
Additionally, we use the [Redhat YAML formatter](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) to have uniform formatting in our `.yaml` files.
|
||||||
|
|
||||||
|
## Code documentation
|
||||||
|
|
||||||
|
Documentation of the latest release are available on [pkg.go.dev](https://pkg.go.dev/github.com/edgelesssys/constellation/v2).
|
||||||
|
|
||||||
|
Alternatively use `pkgsite` to host your own documentation server and view documentation for the local version of your code.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>View installation instructions</summary>
|
||||||
|
|
||||||
|
```shell
|
||||||
|
CONSTELLATION_DIR=</path/to/your/local/report>
|
||||||
|
git clone https://github.com/golang/pkgsite && cd pkgsite
|
||||||
|
go install ./cmd/pkgsite
|
||||||
|
cd "${CONSTELLATION_DIR}
|
||||||
|
pkgsite
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now view the documentation on http://localhost:8080/github.com/edgelesssys/constellation/v2
|
||||||
|
</details>
|
||||||
|
|
||||||
## PR conventions
|
## PR conventions
|
||||||
|
|
||||||
Our changelog is generated from PR titles. Which PR is listed in which category is determined by labels, see the [release.yml](/.github/release.yml).
|
Our changelog is generated from PR titles. Which PR is listed in which category is determined by labels, see the [release.yml](/.github/release.yml).
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
# State
|
# disk-mapper
|
||||||
|
|
||||||
Files and source code for mounting persistent state disks
|
The disk-mapper is a binary that runs during the initramfs of a Constellation node.
|
||||||
|
|
||||||
|
If running on a new node, it handles setting up the node's state disk by creating an integrity protected encrypted partition.
|
||||||
|
|
||||||
|
On a rebooting node, the disk-mapper handles recovery of the node by requesting a decryption key for its state disk.
|
||||||
|
Once the disk is decrypted, the measurement salt is read from disk and used to extend a PCR to mark the node as initialized.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
@ -9,6 +14,6 @@ The integration test requires root privileges since it uses dm-crypt.
|
|||||||
Build and run the test:
|
Build and run the test:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go test -c -tags=integration ./disk-mapper/test/
|
go test -c -tags=integration ./disk-mapper/internal/test/
|
||||||
sudo ./test.test
|
sudo ./test.test
|
||||||
```
|
```
|
||||||
|
@ -4,6 +4,15 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package mapper uses libcryptsetup to format and map crypt devices.
|
||||||
|
|
||||||
|
This is used by the disk-mapper to set up a node's state disk.
|
||||||
|
|
||||||
|
All interaction with libcryptsetup should be done here.
|
||||||
|
|
||||||
|
Warning: This package is not thread safe, since libcryptsetup is not thread safe.
|
||||||
|
*/
|
||||||
package mapper
|
package mapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -24,7 +33,7 @@ import (
|
|||||||
// https://stackoverflow.com/questions/30553386/cryptsetup-backend-safe-with-multithreading
|
// https://stackoverflow.com/questions/30553386/cryptsetup-backend-safe-with-multithreading
|
||||||
var packageLock = sync.Mutex{}
|
var packageLock = sync.Mutex{}
|
||||||
|
|
||||||
// Mapper handles actions for formating and mapping crypt devices.
|
// Mapper handles actions for formatting and mapping crypt devices.
|
||||||
type Mapper struct {
|
type Mapper struct {
|
||||||
device cryptDevice
|
device cryptDevice
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
|
@ -4,6 +4,15 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package recoveryserver implements the gRPC endpoints for recovering a restarting node.
|
||||||
|
|
||||||
|
The endpoint is only available for control-plane nodes,
|
||||||
|
worker nodes should only rejoin the cluster using Constellation's JoinService.
|
||||||
|
|
||||||
|
This endpoint can be used by an admin in case of a complete cluster shutdown,
|
||||||
|
in which case a node is unable to rejoin the cluster automatically.
|
||||||
|
*/
|
||||||
package recoveryserver
|
package recoveryserver
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,11 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package rejoinclient handles the automatic rejoining of a restarting node.
|
||||||
|
|
||||||
|
It does so by continuously sending rejoin requests to the JoinService of available control-plane endpoints.
|
||||||
|
*/
|
||||||
package rejoinclient
|
package rejoinclient
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,11 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package setup handles setting up rejoinclient and recoveryserver for the disk-mapper.
|
||||||
|
|
||||||
|
On success of either of these services, the state disk is decrypted and the node is tainted as initialized by updating it's PCRs.
|
||||||
|
*/
|
||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package systemd configures systemd units for encrypted volumes.
|
||||||
package systemd
|
package systemd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -5,7 +5,7 @@ package recoverproto;
|
|||||||
option go_package = "github.com/edgelesssys/constellation/v2/disk-mapper/recoverproto";
|
option go_package = "github.com/edgelesssys/constellation/v2/disk-mapper/recoverproto";
|
||||||
|
|
||||||
service API {
|
service API {
|
||||||
// Recover sends the necessary information to the recoveryserver to start recovering the cluster.
|
// Recover sends the necessary information to the recoveryserver to initiate recovery of a node.
|
||||||
rpc Recover(RecoverMessage) returns (RecoverResponse) {}
|
rpc Recover(RecoverMessage) returns (RecoverResponse) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
e2e/e2e.go
Normal file
8
e2e/e2e.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// End-to-end tests which are executed from our GitHub action pipelines.
|
||||||
|
package e2e
|
@ -4,6 +4,8 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Provides functionality to easily interact with the K8s API, which can be used
|
||||||
|
// from any e2e test.
|
||||||
package kubectl
|
package kubectl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -6,6 +6,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// End-to-end tests for our cloud load balancer functionality.
|
||||||
package test
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// aTLS provides config generation functions to bootstrap attested TLS connections.
|
||||||
package atls
|
package atls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,28 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This package deals with the low level attestation and verification logic of Constellation nodes.
|
||||||
|
|
||||||
|
General tpm attestation code that is not subjective to a single platform should go into the vtpm package.
|
||||||
|
Since attestation capabilities can differ between platforms, the attestation code should go into a subpackage for that respective platform.
|
||||||
|
|
||||||
|
We commonly implement the following two interfaces for a platform:
|
||||||
|
|
||||||
|
// Issuer issues an attestation document.
|
||||||
|
type Issuer interface {
|
||||||
|
oid.Getter
|
||||||
|
Issue(userData []byte, nonce []byte) (quote []byte, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validator is able to validate an attestation document.
|
||||||
|
type Validator interface {
|
||||||
|
oid.Getter
|
||||||
|
Validate(attDoc []byte, nonce []byte) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
Attestation code for new platforms needs to implement these two interfaces.
|
||||||
|
*/
|
||||||
package attestation
|
package attestation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1 +0,0 @@
|
|||||||
# Amazon Web Services attestation
|
|
30
internal/attestation/aws/aws.go
Normal file
30
internal/attestation/aws/aws.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Amazon Web Services attestation
|
||||||
|
|
||||||
|
Attestation for AWS using [NitroTPM].
|
||||||
|
|
||||||
|
AWS currently does not support confidential VMs, but offers a TPM 2.0 compliant vTPM integration.
|
||||||
|
We use this to enable a TPM based measured boot Constellation deployment.
|
||||||
|
|
||||||
|
# Issuer
|
||||||
|
|
||||||
|
The TPM attestation is signed by the NitroTPM's RSA attestation key.
|
||||||
|
Additionally to the TPM attestation, we attach a node's [instance identity document] to the attestation document.
|
||||||
|
|
||||||
|
# Validator
|
||||||
|
|
||||||
|
Currently, the NitroTPM provides no endorsement certificate for its attestation key, nor does AWS offer a secondary of of verifying it.
|
||||||
|
For now we have to blindly trust the key.
|
||||||
|
|
||||||
|
Additionally to verifying the TPM attestation, we also check the instance identity document for consistency.
|
||||||
|
|
||||||
|
[NitroTPM]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nitrotpm.html
|
||||||
|
[instance identity document]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
|
||||||
|
*/
|
||||||
|
package aws
|
@ -4,6 +4,19 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Azure attestation
|
||||||
|
|
||||||
|
Constellation supports multiple attestation technologies on Azure.
|
||||||
|
|
||||||
|
- SEV - Secure Nested Paging (SEV-SNP)
|
||||||
|
|
||||||
|
TPM attestation verified using an SEV-SNP attestation statement.
|
||||||
|
|
||||||
|
- Trusted Launch
|
||||||
|
|
||||||
|
Basic TPM attestation.
|
||||||
|
*/
|
||||||
package azure
|
package azure
|
||||||
|
|
||||||
import (
|
import (
|
@ -1,19 +0,0 @@
|
|||||||
# SNP
|
|
||||||
|
|
||||||
## Glosssary
|
|
||||||
|
|
||||||
This section explains abbreviations used in SNP implementation.
|
|
||||||
|
|
||||||
### Attestation Key (AK)
|
|
||||||
|
|
||||||
### AMD Root Key (ARK)
|
|
||||||
|
|
||||||
### AMD Signing Key (ASK)
|
|
||||||
|
|
||||||
### Versioned Chip Endorsement Key (VCEK)
|
|
||||||
|
|
||||||
For more information see [SNP WhitePaper](https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf)
|
|
||||||
|
|
||||||
### Host (Hardware?) Compatibility Layer (HCL)
|
|
||||||
|
|
||||||
No public information. Azure compute API has a field `isHostCompatibilityLayerVm`, with only a [single sentence of documentation](https://learn.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=windows).
|
|
43
internal/attestation/azure/snp/snp.go
Normal file
43
internal/attestation/azure/snp/snp.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# SNP
|
||||||
|
|
||||||
|
Attestation based on TPM and SEV-SNP attestation.
|
||||||
|
The TPM is used to generate runtime measurements and signed by an attestation key that can be verified using the SEV-SNP attestation report.
|
||||||
|
|
||||||
|
# Issuer
|
||||||
|
|
||||||
|
Generates a TPM attestation using an attestation key saved in the TPM.
|
||||||
|
Additionally loads the SEV-SNP attestation report and AMD VCEK certificate chain, and adds them to the attestation document.
|
||||||
|
|
||||||
|
# Validator
|
||||||
|
|
||||||
|
Verifies the attestation key used by first verifying the VCEK certificate chain and the SNP attestation report.
|
||||||
|
|
||||||
|
# Glossary
|
||||||
|
|
||||||
|
This section explains abbreviations used in SNP implementation.
|
||||||
|
|
||||||
|
- Attestation Key (AK)
|
||||||
|
|
||||||
|
- AMD Root Key (ARK)
|
||||||
|
|
||||||
|
- AMD Signing Key (ASK)
|
||||||
|
|
||||||
|
- Versioned Chip Endorsement Key (VCEK)
|
||||||
|
|
||||||
|
For more information see [SNP WhitePaper]
|
||||||
|
|
||||||
|
- Host (Hardware?) Compatibility Layer (HCL)
|
||||||
|
|
||||||
|
No public information. Azure compute API has a field `isHostCompatibilityLayerVm`, with only a [single sentence of documentation].
|
||||||
|
|
||||||
|
[SNP WhitePaper]: https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf
|
||||||
|
[single sentence of documentation]: https://learn.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=windows
|
||||||
|
*/
|
||||||
|
package snp
|
22
internal/attestation/azure/trustedlaunch/trustedlaunch.go
Normal file
22
internal/attestation/azure/trustedlaunch/trustedlaunch.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Trusted Launch
|
||||||
|
|
||||||
|
Use Azure's trusted launch vTPM to enable a TPM based measure boot Constellation.
|
||||||
|
|
||||||
|
# Issuer
|
||||||
|
|
||||||
|
Generates a TPM attestation using an attestation key saved in the TPM.
|
||||||
|
Additionally an endorsement certificate of the key, and corresponding CA certificate chain are added to the attestation document.
|
||||||
|
|
||||||
|
# Validator
|
||||||
|
|
||||||
|
Verifies the TPM attestation statement using the public key of the endorsement certificate.
|
||||||
|
The certificate is verified by first verifying its CA certificate chain.
|
||||||
|
*/
|
||||||
|
package trustedlaunch
|
@ -1,75 +0,0 @@
|
|||||||
# Google Cloud Platform attestation
|
|
||||||
|
|
||||||
Google offers [confidential VMs](https://cloud.google.com/compute/confidential-vm/docs/about-cvm), utilizing AMD SEV-ES to provide memory encryption.
|
|
||||||
|
|
||||||
AMD SEV-ES doesn't offer much in terms of remote attestation, and following that the VMs don't offer much either, see [their docs](https://cloud.google.com/compute/confidential-vm/docs/monitoring) on how to validate a confidential VM for some insights.
|
|
||||||
However, each VM comes with a [virtual Trusted Platform Module (vTPM)](https://cloud.google.com/security/shielded-cloud/shielded-vm#vtpm).
|
|
||||||
This module can be used to generate VM unique encryption keys or to attest the platform's chain of boot. We can use the vTPM to verify the VM is running on AMD SEV-ES enabled hardware, allowing us to bootstrap a constellation cluster.
|
|
||||||
|
|
||||||
## vTPM components
|
|
||||||
|
|
||||||
For attestation we make use of multiple vTPM features:
|
|
||||||
|
|
||||||
* Endorsement Key
|
|
||||||
|
|
||||||
Asymemetric key used to establish trust in other keys issued by the TPM or used directly for attestation. The private part never leaves the TPM, while the public part, referred to as Endorsement Public Key (EPK), is available to remote parties. The TPM can issue new keys, signed by its endorsement key, which can then be verified by a remote party using the EPK.
|
|
||||||
|
|
||||||
* Endorsement Publc Key Certificate (EPKC)
|
|
||||||
|
|
||||||
A Certificate signed by the TPM manufacturer verifying the authenticity of the EPK. The public key of the Certificate is the EPK.
|
|
||||||
|
|
||||||
* Event Log
|
|
||||||
|
|
||||||
A log of events over the boot process.
|
|
||||||
|
|
||||||
* [Platform Control Register (PCR)](https://link.springer.com/chapter/10.1007/978-1-4302-6584-9_12)
|
|
||||||
|
|
||||||
Registers holding measurements of software and configuration data. PCR values are not directly written, but updated: a new value is the digest of the old value concatenated with the to be added data.
|
|
||||||
Contents of the PCRs can be signed for attestation. Providing proof to a remote party about software running on the system.
|
|
||||||
|
|
||||||
## Attestation flow
|
|
||||||
|
|
||||||
1. The VM boots and writes its measured software state to the PCRs.
|
|
||||||
|
|
||||||
2. The PCRs are hashed and signed by the EPK.
|
|
||||||
|
|
||||||
3. An attestation statement is created, containing the EPK, the original PCR values, the hashed PCRs, the signature, and the event log.
|
|
||||||
|
|
||||||
4. A remote party establishes trust in the TPMs EPK by verifying its EPKC with the TPM manufactures CA certificate chain.
|
|
||||||
|
|
||||||
Google's vTPMs have no EPKC, instead we querie the GCE API to retrieve a VMs public signing key. This is the public part of the endorsment key used to sign the attestation document.
|
|
||||||
The downside to this is the verifying party requiring permissions to access the GCE API.
|
|
||||||
|
|
||||||
5. The remote party verifies the signature was created by the TPM, and the hash matches the PCRs.
|
|
||||||
|
|
||||||
6. The remote party reads the event log and verifies measuring the event log results in the given PCR values
|
|
||||||
|
|
||||||
7. The software state is now verified, the only thing left to do is to decide if the state is good or not. This is done by comparing the given PCR values to a set of expected PCR values.
|
|
||||||
|
|
||||||
|
|
||||||
## Problems
|
|
||||||
|
|
||||||
* SEV-ES is somewhat limited when compared to the newer version SEV-SNP
|
|
||||||
|
|
||||||
Comparison of SEV, SEV-ES, and SEV-SNP can be seen on page seven of [AMD's SNP whitepaper](https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf#page=7)
|
|
||||||
|
|
||||||
* We have to trust Google
|
|
||||||
|
|
||||||
Since the vTPM is provided by Google, and they could do whatever they want with it, we have no save proof of the VMs actually being confidential.
|
|
||||||
|
|
||||||
* The provided vTPM has no EPKC
|
|
||||||
|
|
||||||
Without a certificate signing the authenticity of any endorsement keys we have no way of establishing a chain of trust.
|
|
||||||
|
|
||||||
|
|
||||||
## Code testing
|
|
||||||
|
|
||||||
Running tests for GCP attestation requires root access on a confidential VM.
|
|
||||||
The VM needs to have read access for the Compute Engine API. This is not an IAM role, but has to be set on the VM itself.
|
|
||||||
|
|
||||||
Build and run the tests:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
go test -c -tags gcp
|
|
||||||
sudo ./gcp.test
|
|
||||||
```
|
|
45
internal/attestation/gcp/gcp.go
Normal file
45
internal/attestation/gcp/gcp.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Google Cloud Platform attestation
|
||||||
|
|
||||||
|
Google offers [confidential VMs], utilizing AMD SEV-ES to provide memory encryption.
|
||||||
|
|
||||||
|
AMD SEV-ES doesn't offer much in terms of remote attestation, and following that the VMs don't offer much either, see [their docs] on how to validate a confidential VM for some insights.
|
||||||
|
However, each VM comes with a [virtual Trusted Platform Module (vTPM)].
|
||||||
|
This module can be used to generate VM unique encryption keys or to attest the platform's chain of boot. We can use the vTPM to verify the VM is running on AMD SEV-ES enabled hardware, allowing us to bootstrap a constellation cluster.
|
||||||
|
|
||||||
|
# Issuer
|
||||||
|
|
||||||
|
Generates a TPM attestation key using a Google provided attestation key.
|
||||||
|
Additionally project ID, zone, and instance name are fetched from the metadata server and attached to the attestation document.
|
||||||
|
|
||||||
|
# Validator
|
||||||
|
|
||||||
|
Verifies the TPM attestation by using a public key provided by Google's API corresponding to the project ID, zone, instance name tuple attached to the attestation document.
|
||||||
|
|
||||||
|
# Problems
|
||||||
|
|
||||||
|
- SEV-ES is somewhat limited when compared to the newer version SEV-SNP
|
||||||
|
|
||||||
|
Comparison of SEV, SEV-ES, and SEV-SNP can be seen on page seven of [AMD's SNP whitepaper]
|
||||||
|
|
||||||
|
- We have to trust Google
|
||||||
|
|
||||||
|
Since the vTPM is provided by Google, and they could do whatever they want with it, we have no save proof of the VMs actually being confidential.
|
||||||
|
|
||||||
|
- The provided vTPM has no endorsement certificate for its attestation key
|
||||||
|
|
||||||
|
Without a certificate signing the authenticity of any endorsement keys we have no way of establishing a chain of trust.
|
||||||
|
Instead, we have to rely on Google's API to provide us with the public key of the vTPM's endorsement key.
|
||||||
|
|
||||||
|
[confidential VMs]: https://cloud.google.com/compute/confidential-vm/docs/about-cvm
|
||||||
|
[their docs]: https://cloud.google.com/compute/confidential-vm/docs/monitoring
|
||||||
|
[virtual Trusted Platform Module (vTPM)]: https://cloud.google.com/security/shielded-cloud/shielded-vm#vtpm
|
||||||
|
[AMD's SNP whitepaper]: https://www.amd.com/system/files/TechDocs/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf#page=7
|
||||||
|
*/
|
||||||
|
package gcp
|
@ -4,6 +4,13 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Measurements
|
||||||
|
|
||||||
|
Defines default expected measurements for the current release, as well as functions for comparing, updating and marshalling measurements.
|
||||||
|
|
||||||
|
This package should not include TPM specific code.
|
||||||
|
*/
|
||||||
package measurements
|
package measurements
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
13
internal/attestation/qemu/qemu.go
Normal file
13
internal/attestation/qemu/qemu.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# QEMU attestation
|
||||||
|
|
||||||
|
Basic TPM attestation for QEMU platforms.
|
||||||
|
This is used for miniConstellation, or QEMU testing clusters.
|
||||||
|
*/
|
||||||
|
package qemu
|
@ -6,6 +6,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// TPM2 simulator used for unit tests.
|
||||||
package simulator
|
package simulator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,53 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Virtual Trusted Platform Module (vTPM)
|
||||||
|
|
||||||
|
This package provides functions to interact with a vTPM.
|
||||||
|
It also implements the low level TPM attestation and verification logic of Constellation's TPM attestation workflow.
|
||||||
|
|
||||||
|
Code that directly interacts with the TPM goes here.
|
||||||
|
|
||||||
|
# vTPM components
|
||||||
|
|
||||||
|
For attestation we make use of multiple vTPM features:
|
||||||
|
|
||||||
|
- Endorsement Key
|
||||||
|
|
||||||
|
Asymmetric key used to establish trust in other keys issued by the TPM or used directly for attestation. The private part never leaves the TPM, while the public part, referred to as Endorsement Public Key (EPK), is available to remote parties. The TPM can issue new keys, signed by its endorsement key, which can then be verified by a remote party using the EPK.
|
||||||
|
|
||||||
|
- Endorsement Public Key Certificate (EPKC)
|
||||||
|
|
||||||
|
A Certificate signed by the TPM manufacturer verifying the authenticity of the EPK. The public key of the Certificate is the EPK.
|
||||||
|
|
||||||
|
- Event Log
|
||||||
|
|
||||||
|
A log of events over the boot process.
|
||||||
|
|
||||||
|
- [Platform Control Register (PCR)]
|
||||||
|
|
||||||
|
Registers holding measurements of software and configuration data. PCR values are not directly written, but updated: a new value is the digest of the old value concatenated with the to be added data.
|
||||||
|
Contents of the PCRs can be signed for attestation. Providing proof to a remote party about software running on the system.
|
||||||
|
|
||||||
|
# Attestation flow
|
||||||
|
|
||||||
|
1. The VM boots and writes its measured software state to the PCRs.
|
||||||
|
|
||||||
|
2. The PCRs are hashed and signed by the EPK.
|
||||||
|
|
||||||
|
3. An attestation statement is created, containing the EPK, the original PCR values, the hashed PCRs, the signature, and the event log.
|
||||||
|
|
||||||
|
4. A remote party establishes trust in the TPMs EPK by verifying its EPKC with the TPM manufactures CA certificate chain.
|
||||||
|
|
||||||
|
5. The remote party verifies the signature was created by the TPM, and the hash matches the PCRs.
|
||||||
|
|
||||||
|
6. The remote party reads the event log and verifies measuring the event log results in the given PCR values
|
||||||
|
|
||||||
|
7. The software state is now verified, the only thing left to do is to decide if the state is good or not. This is done by comparing the given PCR values to a set of expected PCR values.
|
||||||
|
|
||||||
|
[Platform Control Register (PCR)]: https://link.springer.com/chapter/10.1007/978-1-4302-6584-9_12
|
||||||
|
*/
|
||||||
package vtpm
|
package vtpm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,15 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Implements interaction with the AWS API.
|
||||||
|
|
||||||
|
Instance metadata is retrieved from the [AWS IMDS API].
|
||||||
|
|
||||||
|
Retrieving metadata of other instances is done by using the AWS compute API, and requires AWS credentials.
|
||||||
|
|
||||||
|
[AWS IMDS API]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
|
||||||
|
*/
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,15 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Implements interaction with the Azure API.
|
||||||
|
|
||||||
|
Instance metadata is retrieved from the [Azure IMDS API].
|
||||||
|
|
||||||
|
Retrieving metadata of other instances is done by using the Azure API, and requires Azure credentials.
|
||||||
|
|
||||||
|
[Azure IMDS API]: https://docs.microsoft.com/en-us/azure/virtual-machines/linux/instance-metadata-service
|
||||||
|
*/
|
||||||
package azure
|
package azure
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,26 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Cloud
|
||||||
|
|
||||||
|
This package provides functions to interact with cloud providers.
|
||||||
|
This is mainly used to fetch information about the current instance, or other instances of the Constellation cluster.
|
||||||
|
|
||||||
|
Implementation of the cloud provider specific code is done in subpackages named after the CSP.
|
||||||
|
Code that is commonly used by other packages that do not require actual interaction with the CSP API,
|
||||||
|
such as CSP URI string parsing or data types, should go in a <CSP>shared package instead.
|
||||||
|
|
||||||
|
A cloud package should implement the following interface:
|
||||||
|
|
||||||
|
type Cloud interface {
|
||||||
|
List(ctx context.Context) ([]metadata.InstanceMetadata, error)
|
||||||
|
Self(ctx context.Context) (metadata.InstanceMetadata, error)
|
||||||
|
GetLoadBalancerEndpoint(ctx context.Context) (string, error)
|
||||||
|
InitSecretHash(ctx context.Context) ([]byte, error)
|
||||||
|
UID(ctx context.Context) (string, error)
|
||||||
|
}
|
||||||
|
*/
|
||||||
package cloud
|
package cloud
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -4,6 +4,15 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Implements interaction with the GCP API.
|
||||||
|
|
||||||
|
Instance metadata is retrieved from the [GCP metadata API].
|
||||||
|
|
||||||
|
Retrieving metadata of other instances is done by using the GCP compute API, and requires GCP credentials.
|
||||||
|
|
||||||
|
[GCP metadata API]: https://cloud.google.com/compute/docs/storing-retrieving-metadata
|
||||||
|
*/
|
||||||
package gcp
|
package gcp
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,9 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This package provides an interface to fake a CSP API for QEMU instances.
|
||||||
|
*/
|
||||||
package qemu
|
package qemu
|
||||||
|
|
||||||
import (
|
import (
|
@ -8,6 +8,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
// https://github.com/siderolabs/talos/tree/master/hack/docgen
|
// https://github.com/siderolabs/talos/tree/master/hack/docgen
|
||||||
//
|
//
|
||||||
//go:generate docgen ./config.go ./config_doc.go Configuration
|
//go:generate docgen ./config.go ./config_doc.go Configuration
|
||||||
|
|
||||||
|
/*
|
||||||
|
Definitions for Constellation's user config file.
|
||||||
|
|
||||||
|
The config file is used by the CLI to create and manage a Constellation cluster.
|
||||||
|
|
||||||
|
All config relevant definitions, parsing and validation functions should go here.
|
||||||
|
*/
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -394,7 +394,7 @@ func (_ QEMUConfig) Doc() *encoder.Doc {
|
|||||||
func GetConfigurationDoc() *encoder.FileDoc {
|
func GetConfigurationDoc() *encoder.FileDoc {
|
||||||
return &encoder.FileDoc{
|
return &encoder.FileDoc{
|
||||||
Name: "Configuration",
|
Name: "Configuration",
|
||||||
Description: "This binary can be build from siderolabs/talos projects. Located at:\nhttps://github.com/siderolabs/talos/tree/master/hack/docgen\n",
|
Description: "Definitions for Constellation's user config file.\n\nThe config file is used by the CLI to create and manage a Constellation cluster.\n\nAll config relevant definitions, parsing and validation functions should go here.\n",
|
||||||
Structs: []*encoder.Doc{
|
Structs: []*encoder.Doc{
|
||||||
&ConfigDoc,
|
&ConfigDoc,
|
||||||
&UpgradeConfigDoc,
|
&UpgradeConfigDoc,
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package helm provides types and functions shared across services.
|
||||||
package helm
|
package helm
|
||||||
|
|
||||||
// Release bundles all information necessary to create a helm release.
|
// Release bundles all information necessary to create a helm release.
|
||||||
@ -23,7 +24,7 @@ type Releases struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MergeMaps returns a new map that is the merger of it's inputs.
|
// MergeMaps returns a new map that is the merger of it's inputs.
|
||||||
// Key colissions are resolved by taking the value of the second argument (map b).
|
// Key collisions are resolved by taking the value of the second argument (map b).
|
||||||
// Taken from: https://github.com/helm/helm/blob/dbc6d8e20fe1d58d50e6ed30f09a04a77e4c68db/pkg/cli/values/options.go#L91-L108.
|
// Taken from: https://github.com/helm/helm/blob/dbc6d8e20fe1d58d50e6ed30f09a04a77e4c68db/pkg/cli/values/options.go#L91-L108.
|
||||||
func MergeMaps(a, b map[string]any) map[string]any {
|
func MergeMaps(a, b map[string]any) map[string]any {
|
||||||
out := make(map[string]any, len(a))
|
out := make(map[string]any, len(a))
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) Edgeless Systems GmbH
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Unix defines an user creation interface for UNIX systems.
|
|
||||||
type Unix struct{}
|
|
||||||
|
|
||||||
// reference: https://man7.org/linux/man-pages/man8/useradd.8.html#EXIT_VALUES
|
|
||||||
const exitCodeAlreadyInUse = 9
|
|
||||||
|
|
||||||
// CreateUser creates a new user with sudo access.
|
|
||||||
func (u Unix) CreateUser(ctx context.Context, username string) error {
|
|
||||||
cmd := exec.CommandContext(ctx, "useradd", "-m", "-G", "wheel,sudo", username)
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
// do not fail if user already exists
|
|
||||||
if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == exitCodeAlreadyInUse {
|
|
||||||
return ErrUserOrGroupAlreadyExists
|
|
||||||
}
|
|
||||||
return fmt.Errorf("creating a new user failed: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateUserWithSpecificUIDAndGID creates a new user with sudo access and a specific UID and GID.
|
|
||||||
func (u Unix) CreateUserWithSpecificUIDAndGID(ctx context.Context, username string, uid int, gid int) error {
|
|
||||||
// Add group first with the targeted gid
|
|
||||||
cmd := exec.CommandContext(ctx, "groupadd", "-g", strconv.Itoa(gid), username)
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
// do not fail if group already exists
|
|
||||||
if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == exitCodeAlreadyInUse {
|
|
||||||
return ErrUserOrGroupAlreadyExists
|
|
||||||
}
|
|
||||||
return fmt.Errorf("creating a new group failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then, create the user with both the UID and GID assigned.
|
|
||||||
cmd = exec.CommandContext(ctx, "useradd", "-m", "-G", "wheel,sudo", "-u", strconv.Itoa(uid), "-g", strconv.Itoa(gid), username)
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
// do not fail if user already exists
|
|
||||||
if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == exitCodeAlreadyInUse {
|
|
||||||
return ErrUserOrGroupAlreadyExists
|
|
||||||
}
|
|
||||||
return fmt.Errorf("creating a new user: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,215 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) Edgeless Systems GmbH
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrUserDoesNotExist is returned by GetLinuxUser if a linux user does not exist yet.
|
|
||||||
var ErrUserDoesNotExist = errors.New("user does not exist")
|
|
||||||
|
|
||||||
// ErrUserOrGroupAlreadyExists is the Go error converted from the result of useradd or groupadd when an user or group already exists.
|
|
||||||
var ErrUserOrGroupAlreadyExists = errors.New("user or group already exists")
|
|
||||||
|
|
||||||
type passwdParser interface {
|
|
||||||
Parse(fs afero.Fs) (Entries, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type userCreator interface {
|
|
||||||
CreateUser(ctx context.Context, username string) error
|
|
||||||
CreateUserWithSpecificUIDAndGID(ctx context.Context, username string, uid int, gid int) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// LinuxUser holds relevant information about a linux user (subset of /etc/passwd).
|
|
||||||
type LinuxUser struct {
|
|
||||||
Username string
|
|
||||||
Home string
|
|
||||||
UID int
|
|
||||||
GID int
|
|
||||||
}
|
|
||||||
|
|
||||||
// LinuxUserManager can retrieve information on linux users and create new users.
|
|
||||||
type LinuxUserManager struct {
|
|
||||||
Fs afero.Fs
|
|
||||||
Passwd passwdParser
|
|
||||||
Creator userCreator
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLinuxUserManager creates a new LinuxUserManager.
|
|
||||||
func NewLinuxUserManager(fs afero.Fs) LinuxUserManager {
|
|
||||||
return LinuxUserManager{
|
|
||||||
Fs: fs,
|
|
||||||
Passwd: Passwd{},
|
|
||||||
Creator: Unix{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLinuxUserManagerFake creates a new LinuxUserManager that is used for unit tests.
|
|
||||||
func NewLinuxUserManagerFake(fs afero.Fs) LinuxUserManager {
|
|
||||||
return LinuxUserManager{
|
|
||||||
Fs: fs,
|
|
||||||
Passwd: Passwd{},
|
|
||||||
Creator: &StubUserCreator{fs: fs},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StubUserCreator is used for unit tests.
|
|
||||||
type StubUserCreator struct {
|
|
||||||
fs afero.Fs
|
|
||||||
usernames []string
|
|
||||||
uids []int
|
|
||||||
createUserErr error
|
|
||||||
currentUID int
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateUser for StubUserCreator creates an user for an unit test environment.
|
|
||||||
func (s *StubUserCreator) CreateUser(ctx context.Context, username string) error {
|
|
||||||
if stringInSlice(username, s.usernames) {
|
|
||||||
// do not fail if user already exists
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want created users to start at UID 1000
|
|
||||||
if s.currentUID == 0 {
|
|
||||||
s.currentUID = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.createUserErr != nil {
|
|
||||||
return s.createUserErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no predefined error is supposed to happen, increase the UID (unless the file system code fails)
|
|
||||||
if s.fs != nil {
|
|
||||||
lineToWrite := fmt.Sprintf("%s:x:%d:%d:%s:/var/home/%s:/bin/bash\n", username, s.currentUID, s.currentUID, username, username)
|
|
||||||
file, err := s.fs.OpenFile("/etc/passwd", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
n, err := file.WriteString(lineToWrite)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if n != len(lineToWrite) {
|
|
||||||
return errors.New("written text too short")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.currentUID++
|
|
||||||
s.usernames = append(s.usernames, username)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateUserWithSpecificUIDAndGID for StubUserCreator creates an user with a specific UID and GID for an unit test environment.
|
|
||||||
func (s *StubUserCreator) CreateUserWithSpecificUIDAndGID(ctx context.Context, username string, uid int, gid int) error {
|
|
||||||
if stringInSlice(username, s.usernames) {
|
|
||||||
// do not fail if user already exists
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if intInSlice(uid, s.uids) {
|
|
||||||
return errors.New("uid is already used by another user")
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.createUserErr != nil {
|
|
||||||
return s.createUserErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no predefined error is supposed to happen, increase the UID (unless the file system code fails)
|
|
||||||
if s.fs != nil {
|
|
||||||
lineToWrite := fmt.Sprintf("%s:x:%d:%d:%s:/var/home/%s:/bin/bash\n", username, uid, gid, username, username)
|
|
||||||
file, err := s.fs.OpenFile("/etc/passwd", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
n, err := file.WriteString(lineToWrite)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if n != len(lineToWrite) {
|
|
||||||
return errors.New("written text too short")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark UID as used (we don't track GIDs though, as multiple users can belong to one GID)
|
|
||||||
s.uids = append(s.uids, uid)
|
|
||||||
|
|
||||||
// Avoid potential collisions
|
|
||||||
if s.currentUID == uid {
|
|
||||||
s.currentUID++
|
|
||||||
}
|
|
||||||
|
|
||||||
s.usernames = append(s.usernames, username)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLinuxUser tries to find an existing linux user in /etc/passwd.
|
|
||||||
func (l *LinuxUserManager) GetLinuxUser(username string) (LinuxUser, error) {
|
|
||||||
entries, err := l.Passwd.Parse(l.Fs)
|
|
||||||
if err != nil {
|
|
||||||
return LinuxUser{}, err
|
|
||||||
}
|
|
||||||
if _, ok := entries[username]; !ok {
|
|
||||||
return LinuxUser{}, ErrUserDoesNotExist
|
|
||||||
}
|
|
||||||
entry := entries[username]
|
|
||||||
uid, err := strconv.Atoi(entry.UID)
|
|
||||||
if err != nil {
|
|
||||||
return LinuxUser{}, fmt.Errorf("parsing users uid: %w", err)
|
|
||||||
}
|
|
||||||
gid, err := strconv.Atoi(entry.GID)
|
|
||||||
if err != nil {
|
|
||||||
return LinuxUser{}, fmt.Errorf("parsing users gid: %w", err)
|
|
||||||
}
|
|
||||||
return LinuxUser{
|
|
||||||
Username: username,
|
|
||||||
Home: entry.Directory,
|
|
||||||
UID: uid,
|
|
||||||
GID: gid,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnsureLinuxUserExists will try to create the user specified by username and call GetLinuxUser to retrieve user information.
|
|
||||||
func (l *LinuxUserManager) EnsureLinuxUserExists(ctx context.Context, username string) (LinuxUser, error) {
|
|
||||||
// try to create user (even if it already exists)
|
|
||||||
if err := l.Creator.CreateUser(ctx, username); err != nil && !errors.Is(err, ErrUserOrGroupAlreadyExists) {
|
|
||||||
return LinuxUser{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return l.GetLinuxUser(username)
|
|
||||||
}
|
|
||||||
|
|
||||||
// stringInSlice checks if a given string exists in a slice of strings.
|
|
||||||
func stringInSlice(a string, list []string) bool {
|
|
||||||
for _, b := range list {
|
|
||||||
if b == a {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// intInSlice checks if a given string exists in a slice of strings.
|
|
||||||
func intInSlice(a int, list []int) bool {
|
|
||||||
for _, b := range list {
|
|
||||||
if b == a {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) Edgeless Systems GmbH
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"go.uber.org/goleak"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
goleak.VerifyTestMain(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetLinuxUser(t *testing.T) {
|
|
||||||
username := "user"
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
|
||||||
passwdContents string
|
|
||||||
wantErr bool
|
|
||||||
wantUser LinuxUser
|
|
||||||
}{
|
|
||||||
"get works": {
|
|
||||||
passwdContents: "user:x:1000:1000:user:/var/home/user:/bin/bash\n",
|
|
||||||
wantErr: false,
|
|
||||||
wantUser: LinuxUser{
|
|
||||||
Username: "user",
|
|
||||||
Home: "/var/home/user",
|
|
||||||
UID: 1000,
|
|
||||||
GID: 1000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"user does not exist": {
|
|
||||||
passwdContents: "",
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
"parse fails": {
|
|
||||||
passwdContents: "invalid contents\n",
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
"invalid uid": {
|
|
||||||
passwdContents: "user:x:invalid:1000:user:/var/home/user:/bin/bash\n",
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
"invalid gid": {
|
|
||||||
passwdContents: "user:x:1000:invalid:user:/var/home/user:/bin/bash\n",
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, tc := range testCases {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
fs := afero.NewMemMapFs()
|
|
||||||
assert.NoError(afero.WriteFile(fs, "/etc/passwd", []byte(tc.passwdContents), 0o755))
|
|
||||||
manager := NewLinuxUserManagerFake(fs)
|
|
||||||
user, err := manager.GetLinuxUser(username)
|
|
||||||
|
|
||||||
if tc.wantErr {
|
|
||||||
assert.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Equal(tc.wantUser, user)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEnsureLinuxUserExists(t *testing.T) {
|
|
||||||
username := "user"
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
|
||||||
userCreator *StubUserCreator
|
|
||||||
wantErr bool
|
|
||||||
wantUser LinuxUser
|
|
||||||
}{
|
|
||||||
"create works": {
|
|
||||||
userCreator: &StubUserCreator{},
|
|
||||||
wantErr: false,
|
|
||||||
wantUser: LinuxUser{
|
|
||||||
Username: "user",
|
|
||||||
Home: "/var/home/user",
|
|
||||||
UID: 1000,
|
|
||||||
GID: 1000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"create fails": {
|
|
||||||
userCreator: &StubUserCreator{
|
|
||||||
createUserErr: errors.New("create fails"),
|
|
||||||
},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, tc := range testCases {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
fs := afero.NewMemMapFs()
|
|
||||||
manager := NewLinuxUserManagerFake(fs)
|
|
||||||
tc.userCreator.fs = fs
|
|
||||||
manager.Creator = tc.userCreator
|
|
||||||
user, err := manager.EnsureLinuxUserExists(context.Background(), username)
|
|
||||||
|
|
||||||
if tc.wantErr {
|
|
||||||
assert.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Equal(tc.wantUser, user)
|
|
||||||
assert.ElementsMatch([]string{username}, tc.userCreator.usernames)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStringInSlice(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
testSlice := []string{"abc", "efg", "xyz"}
|
|
||||||
|
|
||||||
assert.True(stringInSlice("efg", testSlice))
|
|
||||||
assert.False(stringInSlice("hij", testSlice))
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) Edgeless Systems GmbH
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Entry is an entry of a '/etc/passwd' file.
|
|
||||||
type Entry struct {
|
|
||||||
Password string
|
|
||||||
UID string
|
|
||||||
GID string
|
|
||||||
GECOS string
|
|
||||||
Directory string
|
|
||||||
Shell string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entries contains the information for each user defined in '/etc/passwd'.
|
|
||||||
type Entries map[string]Entry
|
|
||||||
|
|
||||||
// Passwd allows to parse users from '/etc/passwd' on the local system.
|
|
||||||
type Passwd struct{}
|
|
||||||
|
|
||||||
// Parse opens the '/etc/passwd' file and parses it into a map from usernames to Entries.
|
|
||||||
func (p Passwd) Parse(fs afero.Fs) (Entries, error) {
|
|
||||||
return p.parseFile(fs, "/etc/passwd")
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseFile opens the file and parses it into a map from usernames to Entries.
|
|
||||||
func (p Passwd) parseFile(fs afero.Fs, path string) (Entries, error) {
|
|
||||||
file, err := fs.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
entries := Entries{}
|
|
||||||
scanner := bufio.NewScanner(file)
|
|
||||||
|
|
||||||
for scanner.Scan() {
|
|
||||||
// File format: https://man7.org/linux/man-pages/man5/passwd.5.html
|
|
||||||
|
|
||||||
fields := strings.Split(scanner.Text(), ":")
|
|
||||||
if len(fields) != 7 {
|
|
||||||
return nil, errors.New("invalid number of fields")
|
|
||||||
}
|
|
||||||
|
|
||||||
entries[fields[0]] = Entry{
|
|
||||||
Password: fields[1],
|
|
||||||
UID: fields[2],
|
|
||||||
GID: fields[3],
|
|
||||||
GECOS: fields[4],
|
|
||||||
Directory: fields[5],
|
|
||||||
Shell: fields[6],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries, scanner.Err()
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) Edgeless Systems GmbH
|
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
|
||||||
filename := "/etc/passwd"
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
|
||||||
passwdContents string
|
|
||||||
createFile bool
|
|
||||||
wantEntries Entries
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
"parse works": {
|
|
||||||
passwdContents: "root:x:0:0:root:/root:/bin/bash\n",
|
|
||||||
createFile: true,
|
|
||||||
wantEntries: Entries{
|
|
||||||
"root": {
|
|
||||||
Password: "x",
|
|
||||||
UID: "0",
|
|
||||||
GID: "0",
|
|
||||||
GECOS: "root",
|
|
||||||
Directory: "/root",
|
|
||||||
Shell: "/bin/bash",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
"multiple lines": {
|
|
||||||
passwdContents: "root:x:0:0:root:/root:/bin/bash\nfoo:y:1:2:bar:baz:sh",
|
|
||||||
createFile: true,
|
|
||||||
wantEntries: Entries{
|
|
||||||
"root": {
|
|
||||||
Password: "x",
|
|
||||||
UID: "0",
|
|
||||||
GID: "0",
|
|
||||||
GECOS: "root",
|
|
||||||
Directory: "/root",
|
|
||||||
Shell: "/bin/bash",
|
|
||||||
},
|
|
||||||
"foo": {
|
|
||||||
Password: "y",
|
|
||||||
UID: "1",
|
|
||||||
GID: "2",
|
|
||||||
GECOS: "bar",
|
|
||||||
Directory: "baz",
|
|
||||||
Shell: "sh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
"passwd is corrupt": {
|
|
||||||
passwdContents: "too:few:fields\n",
|
|
||||||
createFile: true,
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
"file does not exist": {
|
|
||||||
createFile: false,
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, tc := range testCases {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
require := require.New(t)
|
|
||||||
|
|
||||||
fs := afero.NewMemMapFs()
|
|
||||||
if tc.createFile {
|
|
||||||
assert.NoError(afero.WriteFile(fs, filename, []byte(tc.passwdContents), 0o644))
|
|
||||||
}
|
|
||||||
passwd := Passwd{}
|
|
||||||
entries, err := passwd.Parse(fs)
|
|
||||||
|
|
||||||
if tc.wantErr {
|
|
||||||
assert.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.NoError(err)
|
|
||||||
assert.Equal(tc.wantEntries, entries)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package atlscredentials handles creation of TLS credentials for attested TLS (ATLS).
|
||||||
package atlscredentials
|
package atlscredentials
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package dialer provides a grpc dialer that can be used to create grpc client connections with different levels of ATLS encryption / verification.
|
||||||
package dialer
|
package dialer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package retry provides functions to check if a gRPC error is retryable.
|
||||||
package retry
|
package retry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package testdialer provides a fake dialer for testing.
|
||||||
package testdialer
|
package testdialer
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package installer provides functionality to install binary components of supported kubernetes versions.
|
||||||
package installer
|
package installer
|
||||||
|
|
||||||
import (
|
import (
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package config provides configuration constants for the KeyService.
|
||||||
package config
|
package config
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package aws implements a KMS backend for AWS KMS.
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package azure implements KMS backends for Azure Key Vault and Azure managed HSM.
|
||||||
package azure
|
package azure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,15 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package cluster implements a KMS backend for in cluster key management.
|
||||||
|
|
||||||
|
The cluster backend holds a master key, and corresponding salt.
|
||||||
|
Data Encryption Keys (DEK) are derived from master key and salt using HKDF.
|
||||||
|
|
||||||
|
This backend does not require a storage backend, as keys are derived on demand and not stored anywhere.
|
||||||
|
For that purpose the special NoStoreURI can be used during KMS initialization.
|
||||||
|
*/
|
||||||
package cluster
|
package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,25 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package gcp implements a KMS backend for Google Cloud KMS.
|
||||||
|
|
||||||
|
The following permissions are required for the service account used to authenticate with GCP:
|
||||||
|
|
||||||
|
- cloudkms.cryptoKeyVersions.create
|
||||||
|
|
||||||
|
- cloudkms.cryptoKeyVersions.update
|
||||||
|
|
||||||
|
- cloudkms.cryptoKeyVersions.useToDecrypt
|
||||||
|
|
||||||
|
- cloudkms.cryptoKeyVersions.useToEncrypt
|
||||||
|
|
||||||
|
- cloudkms.importJobs.create
|
||||||
|
|
||||||
|
- cloudkms.importJobs.get
|
||||||
|
|
||||||
|
- cloudkms.importJobs.useToImport
|
||||||
|
*/
|
||||||
package gcp
|
package gcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package kms provides an abstract interface for Key Management Services.
|
||||||
package kms
|
package kms
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package util provides utility functions for the KMS backends.
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,15 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package setup provides functions to create a KMS and key store from a given URI.
|
||||||
|
|
||||||
|
This package does not provide any functionality to interact with the KMS or key store,
|
||||||
|
but only to create them.
|
||||||
|
|
||||||
|
Adding support for a new KMS or storage backend requires adding a new URI for that backend,
|
||||||
|
and implementing the corresponding get*Config function.
|
||||||
|
*/
|
||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,11 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package storage implements storage backends for DEKs.
|
||||||
|
|
||||||
|
If an unset DEK is requested, the backend MUST return [ErrDEKUnset].
|
||||||
|
*/
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,8 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package kubectl provides a kubectl-like interface for Kubernetes.
|
||||||
|
// Functions defined here should not make use of [os/exec].
|
||||||
package kubectl
|
package kubectl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
12
internal/kubernetes/kubernetes.go
Normal file
12
internal/kubernetes/kubernetes.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package kubernetes provides data types and custom marshalers for Kubernetes API objects.
|
||||||
|
|
||||||
|
Interaction with the Kubernetes API should be handled by the kubectl subpackage.
|
||||||
|
*/
|
||||||
|
package kubernetes
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package license provides functions to check a user's Constellation license.
|
||||||
package license
|
package license
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -26,15 +26,15 @@ This can also be used to add context to a single log message:
|
|||||||
|
|
||||||
# Log Levels
|
# Log Levels
|
||||||
|
|
||||||
Use Debugf() to log low level and detailed information that is useful for debugging.
|
Use [Logger.Debugf] to log low level and detailed information that is useful for debugging.
|
||||||
|
|
||||||
Use Infof() to log general information. This method is correct for most logging purposes.
|
Use [Logger.Infof] to log general information. This method is correct for most logging purposes.
|
||||||
|
|
||||||
Use Warnf() to log information that may indicate unwanted behavior, but is not an error.
|
Use [Logger.Warnf] to log information that may indicate unwanted behavior, but is not an error.
|
||||||
|
|
||||||
Use Errorf() to log information about any errors that occurred.
|
Use [Logger.Errorf] to log information about any errors that occurred.
|
||||||
|
|
||||||
Use Fatalf() to log information about any errors that occurred and then exit the program.
|
Use [Logger.Fatalf] to log information about any errors that occurred and then exit the program.
|
||||||
*/
|
*/
|
||||||
package logger
|
package logger
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package nodestate is used to persist the state of a Constellation node to disk.
|
||||||
package nodestate
|
package nodestate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
Copyright (c) Edgeless Systems GmbH
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
Package oid defines OIDs for different CSPs. Currently this is used in attested TLS to distinguish the attestation documents.
|
Package oid defines OIDs for different CSPs. Currently this is used in attested TLS to distinguish the attestation documents.
|
||||||
OIDs beginning with 1.3.9900 are reserved and can be used without registration.
|
OIDs beginning with 1.3.9900 are reserved and can be used without registration.
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package retry provides a simple interface for retrying operations.
|
||||||
package retry
|
package retry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
8
internal/sigstore/sigstore.go
Normal file
8
internal/sigstore/sigstore.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) Edgeless Systems GmbH
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package sigstore is used to verify Constellation components using sigstore, cosign and rekor.
|
||||||
|
package sigstore
|
@ -4,6 +4,11 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package versions defines the supported versions of Constellation components.
|
||||||
|
|
||||||
|
Binaries and container image versions are pinned by their hashes, the generate tool can be found in the hash-generator subpackage.
|
||||||
|
*/
|
||||||
package versions
|
package versions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,17 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This package provides a CLI tool to interact with the Constellation versions API.
|
||||||
|
|
||||||
|
The tool can be used to request information from the API, but also for admin tasks.
|
||||||
|
All actions require an authentication against AWS with the common permissions.
|
||||||
|
Andministrative tasks like adding or removing versions require further AWS permissions
|
||||||
|
as well as permissions to GCP and Azure.
|
||||||
|
|
||||||
|
The CLI is commonly used in the CI pipeline. Most actions shouldn't be executed manually
|
||||||
|
by a developer. Notice that there is no synchronization on API operations.
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -4,6 +4,24 @@ Copyright (c) Edgeless Systems GmbH
|
|||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package client provides a client for the versions API.
|
||||||
|
|
||||||
|
The client needs to be authenticated with AWS. It should be used in internal
|
||||||
|
development and CI tools for administrative tasks. For just fetching information
|
||||||
|
from the API, use the fetcher package instead.
|
||||||
|
|
||||||
|
Needed IAM permissions for read mode:
|
||||||
|
- "s3:GetObject"
|
||||||
|
- "s3:ListBucket"
|
||||||
|
|
||||||
|
Additional needed IAM permissions for write mode:
|
||||||
|
- "s3:PutObject"
|
||||||
|
- "s3:DeleteObject"
|
||||||
|
- "cloudfront:CreateInvalidation"
|
||||||
|
|
||||||
|
Thread-safety of the bucket is not guaranteed. The client is not thread-safe.
|
||||||
|
*/
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -30,20 +48,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Client is the client for the versions API.
|
// Client is the client for the versions API.
|
||||||
//
|
|
||||||
// The client needs to be authenticated with AWS. It is the interface that should
|
|
||||||
// be used in internal development and CI tools.
|
|
||||||
//
|
|
||||||
// Needed IAM permissions for read mode:
|
|
||||||
// - "s3:GetObject"
|
|
||||||
// - "s3:ListBucket"
|
|
||||||
//
|
|
||||||
// Additional needed IAM permissions for write mode:
|
|
||||||
// - "s3:PutObject"
|
|
||||||
// - "s3:DeleteObject"
|
|
||||||
// - "cloudfront:CreateInvalidation"
|
|
||||||
//
|
|
||||||
// Thread-safety of the bucket is not guaranteed. The client is not thread-safe.
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
config aws.Config
|
config aws.Config
|
||||||
cloudfrontClient *cloudfront.Client
|
cloudfrontClient *cloudfront.Client
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user