mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-02-08 02:55:33 -05:00
56beb05170
Signed-off-by: Paul Meyer <49727155+katexochen@users.noreply.github.com>
254 lines
7.3 KiB
Go
254 lines
7.3 KiB
Go
/*
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
package logcollector
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"hash/crc32"
|
|
"io"
|
|
"strings"
|
|
|
|
gcpsecretmanager "cloud.google.com/go/secretmanager/apiv1"
|
|
gcpsecretmanagerpb "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
|
|
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
|
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
|
|
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
|
awssecretmanager "github.com/aws/aws-sdk-go-v2/service/secretsmanager"
|
|
"github.com/edgelesssys/constellation/v2/debugd/internal/debugd/info"
|
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
|
gaxv2 "github.com/googleapis/gax-go/v2"
|
|
)
|
|
|
|
// Credentials contains the credentials for an OpenSearch instance.
|
|
type credentials struct {
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
// credentialGetter is a wrapper around the cloud provider specific credential getters.
|
|
type credentialGetter struct {
|
|
openseachCredsGetter
|
|
}
|
|
|
|
type openseachCredsGetter interface {
|
|
GetOpensearchCredentials(ctx context.Context) (credentials, error)
|
|
io.Closer
|
|
}
|
|
|
|
// NewCloudCredentialGetter returns a new CloudCredentialGetter for the given cloud provider.
|
|
func newCloudCredentialGetter(ctx context.Context, provider cloudprovider.Provider, infoMap *info.Map) (*credentialGetter, error) {
|
|
switch provider {
|
|
case cloudprovider.GCP:
|
|
getter, err := newGCPCloudCredentialGetter(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating GCP cloud credential getter: %w", err)
|
|
}
|
|
return &credentialGetter{getter}, nil
|
|
case cloudprovider.Azure:
|
|
getter, err := newAzureCloudCredentialGetter()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating Azure cloud credential getter: %w", err)
|
|
}
|
|
return &credentialGetter{getter}, nil
|
|
case cloudprovider.AWS:
|
|
getter, err := newAWSCloudCredentialGetter(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating AWS cloud credential getter: %w", err)
|
|
}
|
|
return &credentialGetter{getter}, nil
|
|
case cloudprovider.QEMU:
|
|
getter, err := newQemuCloudCredentialGetter(infoMap)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating QEMU cloud credential getter: %w", err)
|
|
}
|
|
return &credentialGetter{getter}, nil
|
|
default:
|
|
return nil, fmt.Errorf("cloud provider not supported")
|
|
}
|
|
}
|
|
|
|
type gcpCloudCredentialGetter struct {
|
|
secretsAPI gcpSecretManagerAPI
|
|
}
|
|
|
|
func newGCPCloudCredentialGetter(ctx context.Context) (*gcpCloudCredentialGetter, error) {
|
|
client, err := gcpsecretmanager.NewClient(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating secretmanager client: %w", err)
|
|
}
|
|
return &gcpCloudCredentialGetter{secretsAPI: client}, nil
|
|
}
|
|
|
|
func (g *gcpCloudCredentialGetter) GetOpensearchCredentials(ctx context.Context) (credentials, error) {
|
|
const secretName = "projects/796962942582/secrets/e2e-logs-OpenSearch-password/versions/1"
|
|
const username = "cluster-instance-gcp"
|
|
|
|
req := &gcpsecretmanagerpb.AccessSecretVersionRequest{Name: secretName}
|
|
resp, err := g.secretsAPI.AccessSecretVersion(ctx, req)
|
|
if err != nil {
|
|
return credentials{}, fmt.Errorf("accessing secret version: %w", err)
|
|
}
|
|
|
|
if resp.Payload == nil || len(resp.Payload.Data) == 0 {
|
|
return credentials{}, errors.New("response payload is empty")
|
|
}
|
|
|
|
crc32c := crc32.MakeTable(crc32.Castagnoli)
|
|
checksum := int64(crc32.Checksum(resp.Payload.Data, crc32c))
|
|
if checksum != *resp.Payload.DataCrc32C {
|
|
return credentials{}, errors.New("data corruption of secret detected")
|
|
}
|
|
|
|
return credentials{
|
|
Username: username,
|
|
Password: string(resp.Payload.Data),
|
|
}, nil
|
|
}
|
|
|
|
func (g *gcpCloudCredentialGetter) Close() error {
|
|
return g.secretsAPI.Close()
|
|
}
|
|
|
|
type gcpSecretManagerAPI interface {
|
|
AccessSecretVersion(ctx context.Context, req *gcpsecretmanagerpb.AccessSecretVersionRequest,
|
|
opts ...gaxv2.CallOption,
|
|
) (*gcpsecretmanagerpb.AccessSecretVersionResponse, error)
|
|
io.Closer
|
|
}
|
|
|
|
type azureCloudCredentialGetter struct {
|
|
secretsAPI azureSecretsAPI
|
|
}
|
|
|
|
func newAzureCloudCredentialGetter() (*azureCloudCredentialGetter, error) {
|
|
const vaultURI = "https://opensearch-creds.vault.azure.net"
|
|
|
|
cred, err := azidentity.NewDefaultAzureCredential(nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating default azure credential: %w", err)
|
|
}
|
|
|
|
client, err := azsecrets.NewClient(vaultURI, cred, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating Azure secrets client: %w", err)
|
|
}
|
|
|
|
return &azureCloudCredentialGetter{secretsAPI: client}, nil
|
|
}
|
|
|
|
func (a *azureCloudCredentialGetter) GetOpensearchCredentials(ctx context.Context) (credentials, error) {
|
|
const secretName = "opensearch-password"
|
|
const username = "cluster-instance-azure"
|
|
const version = "" // An empty string version gets the latest version of the secret.
|
|
|
|
resp, err := a.secretsAPI.GetSecret(ctx, secretName, version, nil)
|
|
if err != nil {
|
|
return credentials{}, fmt.Errorf("getting secret: %w", err)
|
|
}
|
|
|
|
if resp.Value == nil {
|
|
return credentials{}, errors.New("response value is empty")
|
|
}
|
|
|
|
return credentials{
|
|
Username: username,
|
|
Password: *resp.Value,
|
|
}, nil
|
|
}
|
|
|
|
func (a *azureCloudCredentialGetter) Close() error {
|
|
return nil
|
|
}
|
|
|
|
type azureSecretsAPI interface {
|
|
GetSecret(ctx context.Context, name string, version string, options *azsecrets.GetSecretOptions,
|
|
) (azsecrets.GetSecretResponse, error)
|
|
}
|
|
|
|
type awsCloudCredentialGetter struct {
|
|
secretmanager awsSecretManagerAPI
|
|
}
|
|
|
|
func newAWSCloudCredentialGetter(ctx context.Context) (*awsCloudCredentialGetter, error) {
|
|
const region = "eu-central-1"
|
|
|
|
config, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(region))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("loading default AWS config: %w", err)
|
|
}
|
|
|
|
client := awssecretmanager.NewFromConfig(config)
|
|
|
|
return &awsCloudCredentialGetter{secretmanager: client}, nil
|
|
}
|
|
|
|
func (a *awsCloudCredentialGetter) GetOpensearchCredentials(ctx context.Context) (credentials, error) {
|
|
const username = "cluster-instance-aws"
|
|
secertName := "opensearch-password"
|
|
|
|
req := &awssecretmanager.GetSecretValueInput{SecretId: &secertName}
|
|
resp, err := a.secretmanager.GetSecretValue(ctx, req)
|
|
if err != nil {
|
|
return credentials{}, fmt.Errorf("getting secret value: %w", err)
|
|
}
|
|
|
|
if resp.SecretString == nil {
|
|
return credentials{}, errors.New("response secret string is empty")
|
|
}
|
|
|
|
password := strings.TrimPrefix(*resp.SecretString, "{\"password\":\"")
|
|
password = strings.TrimSuffix(password, "\"}")
|
|
|
|
return credentials{
|
|
Username: username,
|
|
Password: password,
|
|
}, nil
|
|
}
|
|
|
|
func (a *awsCloudCredentialGetter) Close() error {
|
|
return nil
|
|
}
|
|
|
|
type awsSecretManagerAPI interface {
|
|
GetSecretValue(ctx context.Context, params *awssecretmanager.GetSecretValueInput,
|
|
optFns ...func(*awssecretmanager.Options),
|
|
) (*awssecretmanager.GetSecretValueOutput, error)
|
|
}
|
|
|
|
type qemuCloudCredentialGetter struct {
|
|
creds credentials
|
|
}
|
|
|
|
func newQemuCloudCredentialGetter(infoMap *info.Map) (*qemuCloudCredentialGetter, error) {
|
|
const username = "cluster-instance-qemu"
|
|
|
|
password, ok, err := infoMap.Get("qemu.opensearch-pw")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting qemu.opensearch-pw from info: %w", err)
|
|
}
|
|
if !ok {
|
|
return nil, errors.New("qemu.opensearch-pw not found in info")
|
|
}
|
|
|
|
return &qemuCloudCredentialGetter{
|
|
creds: credentials{
|
|
Username: username,
|
|
Password: password,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (q *qemuCloudCredentialGetter) GetOpensearchCredentials(ctx context.Context) (credentials, error) {
|
|
return q.creds, nil
|
|
}
|
|
|
|
func (q *qemuCloudCredentialGetter) Close() error {
|
|
return nil
|
|
}
|