terraform: remove cloud loggers (#2892)

* terraform: remove cloud logging apps

* internal/cloud: remove loggers

* bootstrapper: remove logging

* qemu-metadata-api: remove logging endpoint

* docs: add instructions on how to get boot logs

* bazel: tidy

* docs: fix typo

* cloud: remove unused types

* Update go.mod

Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com>

* bazel: tidy

* Update docs/docs/workflows/troubleshooting.md

Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com>

* Update docs/docs/workflows/troubleshooting.md

Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com>

* Update docs/docs/workflows/troubleshooting.md

Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com>

* docs: elaborate on how to get boot logs

* bazel: tidy

---------

Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com>
Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com>
This commit is contained in:
Moritz Sanft 2024-02-06 14:27:30 +01:00 committed by GitHub
parent dde3430da8
commit 901edd420b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 12 additions and 1456 deletions

View File

@ -343,14 +343,6 @@ def go_dependencies():
sum = "h1:xKbFXea2CIF/Wskauz1TMr//wZ6FyzEafMdSBIQqn80=",
version = "v1.32.6",
)
go_repository(
name = "com_github_aws_aws_sdk_go_v2_service_cloudwatchlogs",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs",
sum = "h1:9apthAVGtCrw6LkswOcRpa1fMWur+7cGqO0yR65qsZM=",
version = "v1.30.2",
)
go_repository(
name = "com_github_aws_aws_sdk_go_v2_service_ec2",
build_file_generation = "on",
@ -511,14 +503,6 @@ def go_dependencies():
sum = "h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw=",
version = "v0.7.1",
)
go_repository(
name = "com_github_azure_azure_sdk_for_go_sdk_resourcemanager_applicationinsights_armapplicationinsights",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights",
sum = "h1:hBrFatNIiVAwDb5GzMLjpkQ6l2/waFSvBWMBWZRH8WI=",
version = "v1.1.1",
)
go_repository(
name = "com_github_azure_azure_sdk_for_go_sdk_resourcemanager_compute_armcompute_v5",
build_file_generation = "on",
@ -3651,14 +3635,6 @@ def go_dependencies():
sum = "h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=",
version = "v0.5.0",
)
go_repository(
name = "com_github_microsoft_applicationinsights_go",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/microsoft/ApplicationInsights-Go",
sum = "h1:G4+H9WNs6ygSCe6sUyxRc2U81TI5Es90b2t/MwX5KqY=",
version = "v0.4.4",
)
go_repository(
name = "com_github_microsoft_go_winio",
build_file_generation = "on",
@ -3995,14 +3971,6 @@ def go_dependencies():
sum = "h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=",
version = "v1.2.8",
)
go_repository(
name = "com_github_onsi_ginkgo",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/onsi/ginkgo",
sum = "h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=",
version = "v1.8.0",
)
go_repository(
name = "com_github_onsi_ginkgo_v2",
build_file_generation = "on",
@ -4819,14 +4787,6 @@ def go_dependencies():
sum = "h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=",
version = "v2.3.1",
)
go_repository(
name = "com_github_tedsuo_ifrit",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "github.com/tedsuo/ifrit",
sum = "h1:LUUe4cdABGrIJAhl1P1ZpWY76AwukVszFdwkVFVLwIk=",
version = "v0.0.0-20180802180643-bea94bb476cc",
)
go_repository(
name = "com_github_theupdateframework_go_tuf",
build_file_generation = "on",
@ -7008,14 +6968,6 @@ def go_dependencies():
sum = "h1:Z96pB6DkSb7F3Y3BBnJeOZH2gazyMTWlvecSD4vDqfk=",
version = "v0.0.7",
)
go_repository(
name = "org_cloudfoundry_code_clock",
build_file_generation = "on",
build_file_proto_mode = "disable_global",
importpath = "code.cloudfoundry.org/clock",
sum = "h1:5eeuG0BHx1+DHeT3AP+ISKZ2ht1UjGhm581ljqYpVeQ=",
version = "v0.0.0-20180518195852-02e53af36e6c",
)
go_repository(
name = "org_golang_google_api",
build_file_generation = "on",

View File

@ -20,7 +20,6 @@ go_library(
"//bootstrapper/internal/kubernetes",
"//bootstrapper/internal/kubernetes/k8sapi",
"//bootstrapper/internal/kubernetes/kubewaiter",
"//bootstrapper/internal/logging",
"//bootstrapper/internal/nodelock",
"//internal/atls",
"//internal/attestation/choose",

View File

@ -19,7 +19,6 @@ import (
"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/kubewaiter"
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/logging"
"github.com/edgelesssys/constellation/v2/internal/attestation/choose"
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
"github.com/edgelesssys/constellation/v2/internal/attestation/tdx"
@ -62,7 +61,6 @@ func main() {
bindPort := strconv.Itoa(constants.BootstrapperPort)
var clusterInitJoiner clusterInitJoiner
var metadataAPI metadataAPI
var cloudLogger logging.CloudLogger
var openDevice vtpm.TPMOpenFunc
var fs afero.Fs
@ -83,11 +81,6 @@ func main() {
}
metadataAPI = metadata
cloudLogger, err = awscloud.NewLogger(ctx)
if err != nil {
log.With(zap.Error(err)).Fatalf("Failed to set up cloud logger")
}
clusterInitJoiner = kubernetes.New(
"aws", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.NewUninitialized(),
metadata, &kubewaiter.CloudKubeAPIWaiter{},
@ -102,11 +95,6 @@ func main() {
}
defer metadata.Close()
cloudLogger, err = gcpcloud.NewLogger(ctx, "constellation-boot-log")
if err != nil {
log.With(zap.Error(err)).Fatalf("Failed to set up cloud logger")
}
metadataAPI = metadata
clusterInitJoiner = kubernetes.New(
"gcp", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.NewUninitialized(),
@ -120,10 +108,7 @@ func main() {
if err != nil {
log.With(zap.Error(err)).Fatalf("Failed to create Azure metadata client")
}
cloudLogger, err = azurecloud.NewLogger(ctx)
if err != nil {
log.With(zap.Error(err)).Fatalf("Failed to set up cloud logger")
}
if err := metadata.PrepareControlPlaneNode(ctx, log); err != nil {
log.With(zap.Error(err)).Fatalf("Failed to prepare Azure control plane node")
}
@ -138,7 +123,6 @@ func main() {
fs = afero.NewOsFs()
case cloudprovider.QEMU:
cloudLogger = qemucloud.NewLogger()
metadata := qemucloud.New()
clusterInitJoiner = kubernetes.New(
"qemu", k8sapi.NewKubernetesUtil(), &k8sapi.KubdeadmConfiguration{}, kubectl.NewUninitialized(),
@ -158,7 +142,6 @@ func main() {
}
fs = afero.NewOsFs()
case cloudprovider.OpenStack:
cloudLogger = &logging.NopLogger{}
metadata, err := openstackcloud.New(ctx)
if err != nil {
log.With(zap.Error(err)).Fatalf("Failed to create OpenStack metadata client")
@ -173,7 +156,6 @@ func main() {
default:
clusterInitJoiner = &clusterFake{}
metadataAPI = &providerMetadataFake{}
cloudLogger = &logging.NopLogger{}
var simulatedTPMCloser io.Closer
openDevice, simulatedTPMCloser = simulator.NewSimulatedTPMOpenFunc()
defer simulatedTPMCloser.Close()
@ -182,5 +164,5 @@ func main() {
fileHandler := file.NewHandler(fs)
run(issuer, openDevice, fileHandler, clusterInitJoiner, metadataAPI, bindIP, bindPort, log, cloudLogger)
run(issuer, openDevice, fileHandler, clusterInitJoiner, metadataAPI, bindIP, bindPort, log)
}

View File

@ -14,7 +14,6 @@ import (
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/diskencryption"
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/initserver"
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/joinclient"
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/logging"
"github.com/edgelesssys/constellation/v2/bootstrapper/internal/nodelock"
"github.com/edgelesssys/constellation/v2/internal/atls"
"github.com/edgelesssys/constellation/v2/internal/attestation/initialize"
@ -29,20 +28,14 @@ import (
func run(issuer atls.Issuer, openDevice vtpm.TPMOpenFunc, fileHandler file.Handler,
kube clusterInitJoiner, metadata metadataAPI,
bindIP, bindPort string, log *logger.Logger,
cloudLogger logging.CloudLogger,
) {
defer cloudLogger.Close()
log.With(zap.String("version", constants.BinaryVersion().String())).Infof("Starting bootstrapper")
cloudLogger.Disclose("bootstrapper started running...")
uuid, err := getDiskUUID()
if err != nil {
log.With(zap.Error(err)).Errorf("Failed to get disk UUID")
cloudLogger.Disclose("Failed to get disk UUID")
} else {
log.Infof("Disk UUID: %s", uuid)
cloudLogger.Disclose("Disk UUID: " + uuid)
}
nodeBootstrapped, err := initialize.IsNodeBootstrapped(openDevice)
@ -77,7 +70,6 @@ func run(issuer atls.Issuer, openDevice vtpm.TPMOpenFunc, fileHandler file.Handl
}
log.Infof("bootstrapper done")
cloudLogger.Disclose("bootstrapper done")
}
func getDiskUUID() (string, error) {

View File

@ -95,49 +95,14 @@ check if the encountered [issue is known](https://github.com/edgelesssys/constel
## Diagnosing issues
### Cloud logging
### Logs
To provide information during early stages of a node's boot process, Constellation logs messages to the log systems of the cloud providers. Since these offerings **aren't** confidential, only generic information without any sensitive values is stored. This provides administrators with a high-level understanding of the current state of a node.
To get started on diagnosing issues with Constellation, it's often helpful to collect logs from nodes, pods, or other resources in the cluster. Most logs are available through Kubernetes' standard
[logging interfaces](https://kubernetes.io/docs/concepts/cluster-administration/logging/).
You can view this information in the following places:
To debug issues occurring at boot time of the nodes, you can use the serial console interface of the CSP while the machine boots to get a read-only view of the boot logs.
<tabs groupId="csp">
<tabItem value="azure" label="Azure">
1. In your Azure subscription find the Constellation resource group.
2. Inside the resource group find the Application Insights resource called `constellation-insights-*`.
3. On the left-hand side go to `Logs`, which is located in the section `Monitoring`.
- Close the Queries page if it pops up.
5. In the query text field type in `traces`, and click `Run`.
To **find the disk UUIDs** use the following query: `traces | where message contains "Disk UUID"`
</tabItem>
<tabItem value="gcp" label="GCP">
1. Select the project that hosts Constellation.
2. Go to the `Compute Engine` service.
3. On the right-hand side of a VM entry select `More Actions` (a stacked ellipsis)
- Select `View logs`
To **find the disk UUIDs** use the following query: `resource.type="gce_instance" text_payload=~"Disk UUID:.*\n" logName=~".*/constellation-boot-log"`
:::info
Constellation uses the default bucket to store logs. Its [default retention period is 30 days](https://cloud.google.com/logging/quotas#logs_retention_periods).
:::
</tabItem>
<tabItem value="aws" label="AWS">
1. Open [AWS CloudWatch](https://console.aws.amazon.com/cloudwatch/home)
2. Select [Log Groups](https://console.aws.amazon.com/cloudwatch/home#logsV2:log-groups)
3. Select the log group that matches the name of your cluster.
4. Select the log stream for control or worker type nodes.
</tabItem>
</tabs>
Apart from that, Constellation also offers further [observability integrations](../architecture/observability.md).
### Node shell access

9
go.mod
View File

@ -44,7 +44,6 @@ require (
cloud.google.com/go/compute v1.23.0
cloud.google.com/go/compute/metadata v0.2.3
cloud.google.com/go/kms v1.15.2
cloud.google.com/go/logging v1.8.1
cloud.google.com/go/secretmanager v1.11.1
cloud.google.com/go/storage v1.31.0
dario.cat/mergo v1.0.0
@ -52,11 +51,9 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v1.1.1
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.1.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v5 v5.0.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0
github.com/Azure/go-autorest/autorest/to v0.4.0
github.com/aws/aws-sdk-go v1.44.297
github.com/aws/aws-sdk-go-v2 v1.24.1
github.com/aws/aws-sdk-go-v2/config v1.26.3
@ -65,7 +62,6 @@ require (
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.11
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.36.7
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.32.6
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.30.2
github.com/aws/aws-sdk-go-v2/service/ec2 v1.143.0
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.26.7
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.19.7
@ -110,7 +106,6 @@ require (
github.com/hexops/gotextdiff v1.0.3
github.com/martinjungblut/go-cryptsetup v0.0.0-20220520180014-fd0874fd07a6
github.com/mattn/go-isatty v0.0.20
github.com/microsoft/ApplicationInsights-Go v0.4.4
github.com/onsi/ginkgo/v2 v2.13.0
github.com/onsi/gomega v1.29.0
github.com/pkg/errors v0.9.1
@ -161,8 +156,6 @@ require (
require (
cloud.google.com/go v0.110.8 // indirect
cloud.google.com/go/iam v1.1.2 // indirect
cloud.google.com/go/longrunning v0.5.1 // indirect
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect
@ -173,6 +166,7 @@ require (
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
@ -248,7 +242,6 @@ require (
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect

25
go.sum
View File

@ -35,10 +35,6 @@ cloud.google.com/go/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4=
cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
cloud.google.com/go/kms v1.15.2 h1:lh6qra6oC4AyWe5fUUUBe/S27k12OHAleOOOw6KakdE=
cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w=
cloud.google.com/go/logging v1.8.1 h1:26skQWPeYhvIasWKm48+Eq7oUqdcdbwsCVwz5Ys0FvU=
cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI=
cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI=
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@ -53,8 +49,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.google.com/go/storage v1.31.0 h1:+S3LjjEN2zZ+L5hOwj4+1OkGCsLVe0NzpXKQ1pSdTCI=
cloud.google.com/go/storage v1.31.0/go.mod h1:81ams1PrhW16L4kF7qg+4mTq7SRs5HsbDTM0bWvrwJ0=
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c h1:5eeuG0BHx1+DHeT3AP+ISKZ2ht1UjGhm581ljqYpVeQ=
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
@ -74,8 +68,6 @@ github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 h1:xnO4sFyG8UH2
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0/go.mod h1:XD3DIOOVgBCO03OleB1fHjgktVRFxlT++KwKgIOewdM=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v1.1.1 h1:hBrFatNIiVAwDb5GzMLjpkQ6l2/waFSvBWMBWZRH8WI=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v1.1.1/go.mod h1:uxknLoFj+nBXpfGngz0B4ciNur04Y0EX4AREpy2GIvk=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.1.0 h1:Sg/D8VuUQ+bw+FOYJF+xRKcwizCOP13HL0Se8pWNBzE=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.1.0/go.mod h1:Kyqzdqq0XDoCm+o9aZ25wZBmBUBzPBzPAj1R5rYsT6I=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E=
@ -189,8 +181,6 @@ github.com/aws/aws-sdk-go-v2/service/autoscaling v1.36.7 h1:Vy2KdIN8tGSKBhwvjbWQ
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.36.7/go.mod h1:D5vhsHh8cnUikp91klW0VIEGG/ygAWiUOmGZU+Q4iZ0=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.32.6 h1:xKbFXea2CIF/Wskauz1TMr//wZ6FyzEafMdSBIQqn80=
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.32.6/go.mod h1:iB6PQSb3ULRrrlEiuFfVE318JiBOdk4k46BbuzrrgXc=
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.30.2 h1:9apthAVGtCrw6LkswOcRpa1fMWur+7cGqO0yR65qsZM=
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.30.2/go.mod h1:jZNaJEtn9TLi3pfxycLz79HVkKxP8ZdYm92iaNFgBsA=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.143.0 h1:ZAO4y7MSRqU74ZFCA+HC6Ek5fI7dsTdwJg88s72I/gE=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.143.0/go.mod h1:hIsHE0PaWAQakLCshKS7VKWMGXaqrAFp4m95s2W9E6c=
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.26.7 h1:ystNRv96lPnlDFU/K3O4/erHR+kPaiDbDGi/192uXQ4=
@ -344,7 +334,6 @@ github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6
github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
@ -467,9 +456,6 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@ -683,7 +669,6 @@ github.com/honeycombio/libhoney-go v1.16.0 h1:kPpqoz6vbOzgp7jC6SR7SkNj7rua7rgxvz
github.com/honeycombio/libhoney-go v1.16.0/go.mod h1:izP4fbREuZ3vqC4HlCAmPrcPT9gxyxejRjGtCYpmBn0=
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM=
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
@ -793,8 +778,6 @@ github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/microsoft/ApplicationInsights-Go v0.4.4 h1:G4+H9WNs6ygSCe6sUyxRc2U81TI5Es90b2t/MwX5KqY=
github.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
@ -845,11 +828,8 @@ github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@ -968,7 +948,6 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0=
github.com/theupdateframework/go-tuf v0.5.2 h1:habfDzTmpbzBLIFGWa2ZpVhYvFBoK0C1onC3a4zuPRA=
github.com/theupdateframework/go-tuf v0.5.2/go.mod h1:SyMV5kg5n4uEclsyxXJZI2UxPFJNDc4Y+r7wv+MlvTA=
github.com/thomasten/go-tpm v0.0.0-20230629092004-f43f8e2a59eb h1:840nUyrM9df2aLuzWuIkYx/DrUbX4KQZO6B9LD45aWo=
@ -1131,7 +1110,6 @@ golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1203,7 +1181,6 @@ golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1473,12 +1450,10 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -9,7 +9,6 @@ package server
import (
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"strings"
@ -44,7 +43,6 @@ func (s *Server) ListenAndServe(port string) error {
mux := http.NewServeMux()
mux.Handle("/self", http.HandlerFunc(s.listSelf))
mux.Handle("/peers", http.HandlerFunc(s.listPeers))
mux.Handle("/log", http.HandlerFunc(s.postLog))
mux.Handle("/endpoint", http.HandlerFunc(s.getEndpoint))
mux.Handle("/initsecrethash", http.HandlerFunc(s.initSecretHash))
@ -173,33 +171,6 @@ func (s *Server) getEndpoint(w http.ResponseWriter, r *http.Request) {
http.Error(w, "No matching peer found", http.StatusNotFound)
}
// postLog writes implements cloud-logging for QEMU instances.
func (s *Server) postLog(w http.ResponseWriter, r *http.Request) {
log := s.log.With(zap.String("peer", r.RemoteAddr))
if r.Method != http.MethodPost {
log.With(zap.String("method", r.Method)).Errorf("Invalid method for /log")
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
log.Infof("Serving POST request for /log")
if r.Body == nil {
log.Errorf("Request body is empty")
http.Error(w, "Request body is empty", http.StatusBadRequest)
return
}
msg, err := io.ReadAll(r.Body)
if err != nil {
log.With(zap.Error(err)).Errorf("Failed to read request body")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
log.With(zap.String("message", string(msg))).Infof("Cloud-logging entry")
}
// listAll returns a list of all active peers.
func (s *Server) listAll() ([]metadata.InstanceMetadata, error) {
net, err := s.virt.LookupNetworkByName(s.network)

View File

@ -13,7 +13,6 @@ import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/edgelesssys/constellation/v2/hack/qemu-metadata-api/virtwrapper"
@ -223,55 +222,6 @@ func TestListPeers(t *testing.T) {
}
}
func TestPostLog(t *testing.T) {
testCases := map[string]struct {
remoteAddr string
message io.Reader
method string
wantErr bool
}{
"success": {
remoteAddr: "192.0.100.1:1234",
method: http.MethodPost,
message: strings.NewReader("test message"),
},
"no body": {
remoteAddr: "192.0.100.1:1234",
method: http.MethodPost,
message: nil,
wantErr: true,
},
"incorrect method": {
remoteAddr: "192.0.100.1:1234",
method: http.MethodGet,
message: strings.NewReader("test message"),
wantErr: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
server := New(logger.NewTest(t), "test", "initSecretHash", &stubConnect{})
req, err := http.NewRequestWithContext(context.Background(), tc.method, "http://192.0.0.1/logs", tc.message)
require.NoError(err)
req.RemoteAddr = tc.remoteAddr
w := httptest.NewRecorder()
server.postLog(w, req)
if tc.wantErr {
assert.NotEqual(http.StatusOK, w.Code)
} else {
assert.Equal(http.StatusOK, w.Code)
}
})
}
}
func TestInitSecretHash(t *testing.T) {
defaultConnect := &stubConnect{
network: newStubNetwork([]virtwrapper.NetworkDHCPLease{

View File

@ -3,10 +3,7 @@ load("//bazel/go:go_test.bzl", "go_test")
go_library(
name = "aws",
srcs = [
"aws.go",
"logger.go",
],
srcs = ["aws.go"],
importpath = "github.com/edgelesssys/constellation/v2/internal/cloud/aws",
visibility = ["//:__subpackages__"],
deps = [
@ -17,24 +14,18 @@ go_library(
"@com_github_aws_aws_sdk_go_v2//aws",
"@com_github_aws_aws_sdk_go_v2_config//:config",
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
"@com_github_aws_aws_sdk_go_v2_service_cloudwatchlogs//:cloudwatchlogs",
"@com_github_aws_aws_sdk_go_v2_service_cloudwatchlogs//types",
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
"@com_github_aws_aws_sdk_go_v2_service_ec2//types",
"@com_github_aws_aws_sdk_go_v2_service_elasticloadbalancingv2//:elasticloadbalancingv2",
"@com_github_aws_aws_sdk_go_v2_service_elasticloadbalancingv2//types",
"@com_github_aws_aws_sdk_go_v2_service_resourcegroupstaggingapi//:resourcegroupstaggingapi",
"@com_github_aws_aws_sdk_go_v2_service_resourcegroupstaggingapi//types",
"@io_k8s_utils//clock",
],
)
go_test(
name = "aws_test",
srcs = [
"aws_test.go",
"logger_test.go",
],
srcs = ["aws_test.go"],
embed = [":aws"],
deps = [
"//internal/cloud",
@ -42,8 +33,6 @@ go_test(
"//internal/role",
"@com_github_aws_aws_sdk_go_v2//aws",
"@com_github_aws_aws_sdk_go_v2_feature_ec2_imds//:imds",
"@com_github_aws_aws_sdk_go_v2_service_cloudwatchlogs//:cloudwatchlogs",
"@com_github_aws_aws_sdk_go_v2_service_cloudwatchlogs//types",
"@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2",
"@com_github_aws_aws_sdk_go_v2_service_ec2//types",
"@com_github_aws_aws_sdk_go_v2_service_elasticloadbalancingv2//:elasticloadbalancingv2",
@ -51,8 +40,5 @@ go_test(
"@com_github_aws_aws_sdk_go_v2_service_resourcegroupstaggingapi//:resourcegroupstaggingapi",
"@com_github_aws_aws_sdk_go_v2_service_resourcegroupstaggingapi//types",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
"@io_k8s_utils//clock/testing",
"@org_uber_go_goleak//:goleak",
],
)

View File

@ -36,10 +36,6 @@ import (
"github.com/edgelesssys/constellation/v2/internal/role"
)
const (
tagName = "Name"
)
type resourceAPI interface {
GetResources(context.Context, *resourcegroupstaggingapi.GetResourcesInput, ...func(*resourcegroupstaggingapi.Options)) (*resourcegroupstaggingapi.GetResourcesOutput, error)
}

View File

@ -1,228 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package aws
import (
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
logs "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
"github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/edgelesssys/constellation/v2/internal/cloud"
"k8s.io/utils/clock"
)
// Logger is a Cloud Logger for AWS.
// Log messages are collected and periodically flushed to AWS Cloudwatch Logs.
type Logger struct {
api logAPI
ec2API ec2API
imdsAPI imdsAPI
groupName string
streamName string
logs []types.InputLogEvent
sequenceToken *string
mux sync.Mutex
interval time.Duration
clock clock.WithTicker
wg sync.WaitGroup
stopCh chan struct{}
}
// NewLogger creates a new Cloud Logger for AWS.
func NewLogger(ctx context.Context) (*Logger, error) {
cfg, err := config.LoadDefaultConfig(ctx, config.WithEC2IMDSRegion())
if err != nil {
return nil, err
}
client := logs.NewFromConfig(cfg)
l := &Logger{
api: client,
ec2API: ec2.NewFromConfig(cfg),
imdsAPI: imds.NewFromConfig(cfg),
interval: time.Second,
clock: clock.RealClock{},
wg: sync.WaitGroup{},
stopCh: make(chan struct{}, 1),
}
if err := l.createStream(ctx); err != nil {
return nil, err
}
l.flushLoop()
return l, nil
}
// Disclose adds a message to the log queue.
// The messages are flushed periodically to AWS Cloudwatch Logs.
func (l *Logger) Disclose(msg string) {
l.mux.Lock()
defer l.mux.Unlock()
l.logs = append(l.logs, types.InputLogEvent{
Message: aws.String(msg),
Timestamp: aws.Int64(l.clock.Now().UnixMilli()),
})
}
// Close flushes the logs a final time and stops the flush loop.
func (l *Logger) Close() error {
l.stopCh <- struct{}{}
l.wg.Wait()
return l.flushLogs()
}
// flushLogs flushes the aggregated log messages to AWS Cloudwatch Logs.
func (l *Logger) flushLogs() error {
// make sure only one flush operation is running at a time
l.mux.Lock()
defer l.mux.Unlock()
if len(l.logs) == 0 {
return nil // no logs to flush
}
ctx := context.Background()
logRequest := &logs.PutLogEventsInput{
LogEvents: l.logs,
LogGroupName: &l.groupName,
LogStreamName: &l.streamName,
SequenceToken: l.sequenceToken,
}
for res, err := l.api.PutLogEvents(ctx, logRequest); ; res, err = l.api.PutLogEvents(ctx, logRequest) {
if err == nil {
l.sequenceToken = res.NextSequenceToken
l.logs = nil
return nil
}
// If the flush operation was called on a pre-existing stream,
// or another operation sent logs to the same stream,
// the sequence token may not be set correctly.
// We can retrieve the correct sequence token from the error message.
var sequenceErr *types.InvalidSequenceTokenException
if !errors.As(err, &sequenceErr) {
return err
}
logRequest.SequenceToken = sequenceErr.ExpectedSequenceToken
}
}
// flushLoop periodically flushes the logs to AWS Cloudwatch Logs.
func (l *Logger) flushLoop() {
l.wg.Add(1)
ticker := l.clock.NewTicker(l.interval)
go func() {
defer l.wg.Done()
defer ticker.Stop()
for {
_ = l.flushLogs()
select {
case <-ticker.C():
case <-l.stopCh:
return
}
}
}()
}
// createStream creates a new log stream in AWS Cloudwatch Logs.
func (l *Logger) createStream(ctx context.Context) error {
name, uid, err := l.getNameAndUID(ctx)
if err != nil {
return err
}
l.streamName = name
// find log group with matching Constellation UID
describeInput := &logs.DescribeLogGroupsInput{}
for res, err := l.api.DescribeLogGroups(ctx, describeInput); ; res, err = l.api.DescribeLogGroups(ctx, describeInput) {
if err != nil {
return err
}
for _, group := range res.LogGroups {
tags, err := l.api.ListTagsLogGroup(ctx, &logs.ListTagsLogGroupInput{LogGroupName: group.LogGroupName})
if err != nil {
continue // we may not have permission to read the tags of a log group outside the Constellation scope
}
if tags.Tags[cloud.TagUID] == uid {
l.groupName = *group.LogGroupName
res.NextToken = nil // stop pagination
break
}
}
if res.NextToken == nil {
break
}
describeInput.NextToken = res.NextToken
}
if l.groupName == "" {
return fmt.Errorf("failed to find log group for UID %s", uid)
}
// create or use existing log stream
if _, err := l.api.CreateLogStream(ctx, &logs.CreateLogStreamInput{
LogGroupName: &l.groupName,
LogStreamName: &l.streamName,
}); err != nil {
// Ignore error if the stream already exists
var createErr *types.ResourceAlreadyExistsException
if !errors.As(err, &createErr) {
return err
}
}
return nil
}
func (l *Logger) getNameAndUID(ctx context.Context) (string, string, error) {
identity, err := l.imdsAPI.GetInstanceIdentityDocument(ctx, &imds.GetInstanceIdentityDocumentInput{})
if err != nil {
return "", "", fmt.Errorf("retrieving instance identity: %w", err)
}
out, err := l.ec2API.DescribeInstances(ctx, &ec2.DescribeInstancesInput{
InstanceIds: []string{identity.InstanceID},
})
if err != nil {
return "", "", fmt.Errorf("descibing instances: %w", err)
}
if len(out.Reservations) != 1 || len(out.Reservations[0].Instances) != 1 {
return "", "", fmt.Errorf("expected 1 instance, got %d", len(out.Reservations[0].Instances))
}
uid, err := findTag(out.Reservations[0].Instances[0].Tags, cloud.TagUID)
if err != nil {
return "", "", fmt.Errorf("finding tag %s: %w", cloud.TagUID, err)
}
return identity.InstanceID, uid, err
}
type logAPI interface {
CreateLogStream(context.Context, *logs.CreateLogStreamInput, ...func(*logs.Options)) (*logs.CreateLogStreamOutput, error)
DescribeLogGroups(context.Context, *logs.DescribeLogGroupsInput, ...func(*logs.Options)) (*logs.DescribeLogGroupsOutput, error)
ListTagsLogGroup(context.Context, *logs.ListTagsLogGroupInput, ...func(*logs.Options)) (*logs.ListTagsLogGroupOutput, error)
PutLogEvents(context.Context, *logs.PutLogEventsInput, ...func(*logs.Options)) (*logs.PutLogEventsOutput, error)
}

View File

@ -1,554 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package aws
import (
"context"
"errors"
"strconv"
"sync"
"testing"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
logs "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types"
"github.com/aws/aws-sdk-go-v2/service/ec2"
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/edgelesssys/constellation/v2/internal/cloud"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
testclock "k8s.io/utils/clock/testing"
)
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m, goleak.IgnoreAnyFunction("github.com/bazelbuild/rules_go/go/tools/bzltestutil.RegisterTimeoutHandler.func1"))
}
func TestCreateStream(t *testing.T) {
someErr := errors.New("failed")
testCases := map[string]struct {
imdsAPI *stubIMDS
ec2API *stubEC2
logs *stubLogs
wantGroup string
wantStream string
wantErr bool
}{
"success new stream minimal": {
imdsAPI: &stubIMDS{
instanceDocumentResp: &imds.GetInstanceIdentityDocumentOutput{
InstanceIdentityDocument: imds.InstanceIdentityDocument{
InstanceID: "test-instance",
},
},
},
ec2API: &stubEC2{
selfInstance: &ec2.DescribeInstancesOutput{
Reservations: []ec2types.Reservation{
{
Instances: []ec2types.Instance{
{
InstanceId: aws.String("test-instance"),
Tags: []ec2types.Tag{
{
Key: aws.String(tagName),
Value: aws.String("test-instance"),
},
{
Key: aws.String(cloud.TagUID),
Value: aws.String("uid"),
},
},
},
},
},
},
},
},
logs: &stubLogs{
describeRes1: &logs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchtypes.LogGroup{
{LogGroupName: aws.String("test-group")},
},
},
listTags: map[string]map[string]string{"test-group": {cloud.TagUID: "uid"}},
},
wantStream: "test-instance",
wantGroup: "test-group",
},
"success one group of many": {
imdsAPI: &stubIMDS{
instanceDocumentResp: &imds.GetInstanceIdentityDocumentOutput{
InstanceIdentityDocument: imds.InstanceIdentityDocument{
InstanceID: "test-instance",
},
},
},
ec2API: &stubEC2{
selfInstance: &ec2.DescribeInstancesOutput{
Reservations: []ec2types.Reservation{
{
Instances: []ec2types.Instance{
{
InstanceId: aws.String("test-instance"),
Tags: []ec2types.Tag{
{
Key: aws.String(tagName),
Value: aws.String("test-instance"),
},
{
Key: aws.String(cloud.TagUID),
Value: aws.String("uid"),
},
},
},
},
},
},
},
},
logs: &stubLogs{
describeRes1: &logs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchtypes.LogGroup{
{
LogGroupName: aws.String("random-group"),
},
{
LogGroupName: aws.String("other-group"),
},
},
NextToken: aws.String("next"),
},
describeRes2: &logs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchtypes.LogGroup{
{
LogGroupName: aws.String("another-group"),
},
{
LogGroupName: aws.String("test-group"),
},
},
},
listTags: map[string]map[string]string{
"random-group": {
"some-tag": "random-tag",
},
"other-group": {
cloud.TagUID: "other-uid",
},
"another-group": {
"some-tag": "uid",
},
"test-group": {
cloud.TagUID: "uid",
},
},
},
wantStream: "test-instance",
wantGroup: "test-group",
},
"success stream exists": {
imdsAPI: &stubIMDS{
instanceDocumentResp: &imds.GetInstanceIdentityDocumentOutput{
InstanceIdentityDocument: imds.InstanceIdentityDocument{
InstanceID: "test-instance",
},
},
},
ec2API: &stubEC2{
selfInstance: &ec2.DescribeInstancesOutput{
Reservations: []ec2types.Reservation{
{
Instances: []ec2types.Instance{
{
InstanceId: aws.String("test-instance"),
Tags: []ec2types.Tag{
{
Key: aws.String(tagName),
Value: aws.String("test-instance"),
},
{
Key: aws.String(cloud.TagUID),
Value: aws.String("uid"),
},
},
},
},
},
},
},
},
logs: &stubLogs{
describeRes1: &logs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchtypes.LogGroup{
{LogGroupName: aws.String("test-group")},
},
},
listTags: map[string]map[string]string{"test-group": {cloud.TagUID: "uid"}},
createErr: &cloudwatchtypes.ResourceAlreadyExistsException{},
},
wantStream: "test-instance",
wantGroup: "test-group",
},
"create stream error": {
imdsAPI: &stubIMDS{
instanceDocumentResp: &imds.GetInstanceIdentityDocumentOutput{
InstanceIdentityDocument: imds.InstanceIdentityDocument{
InstanceID: "test-instance",
},
},
},
ec2API: &stubEC2{
selfInstance: &ec2.DescribeInstancesOutput{
Reservations: []ec2types.Reservation{
{
Instances: []ec2types.Instance{
{
InstanceId: aws.String("test-instance"),
Tags: []ec2types.Tag{
{
Key: aws.String(tagName),
Value: aws.String("test-instance"),
},
{
Key: aws.String(cloud.TagUID),
Value: aws.String("uid"),
},
},
},
},
},
},
},
},
logs: &stubLogs{
describeRes1: &logs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchtypes.LogGroup{
{LogGroupName: aws.String("test-group")},
},
},
listTags: map[string]map[string]string{"test-group": {cloud.TagUID: "uid"}},
createErr: someErr,
},
wantErr: true,
},
"missing uid tag": {
imdsAPI: &stubIMDS{
instanceDocumentResp: &imds.GetInstanceIdentityDocumentOutput{
InstanceIdentityDocument: imds.InstanceIdentityDocument{
InstanceID: "test-instance",
},
},
},
ec2API: &stubEC2{
selfInstance: &ec2.DescribeInstancesOutput{
Reservations: []ec2types.Reservation{
{
Instances: []ec2types.Instance{
{
InstanceId: aws.String("test-instance"),
Tags: []ec2types.Tag{
{
Key: aws.String(tagName),
Value: aws.String("test-instance"),
},
},
},
},
},
},
},
},
logs: &stubLogs{
describeRes1: &logs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchtypes.LogGroup{
{LogGroupName: aws.String("test-group")},
},
},
listTags: map[string]map[string]string{"test-group": {cloud.TagUID: "uid"}},
},
wantErr: true,
},
"missing identity document": {
imdsAPI: &stubIMDS{
getInstanceIdentityDocumentErr: assert.AnError,
},
ec2API: &stubEC2{
selfInstance: &ec2.DescribeInstancesOutput{
Reservations: []ec2types.Reservation{
{
Instances: []ec2types.Instance{
{
InstanceId: aws.String("test-instance"),
Tags: []ec2types.Tag{
{
Key: aws.String(cloud.TagUID),
Value: aws.String("uid"),
},
},
},
},
},
},
},
},
logs: &stubLogs{
describeRes1: &logs.DescribeLogGroupsOutput{
LogGroups: []cloudwatchtypes.LogGroup{
{LogGroupName: aws.String("test-group")},
},
},
listTags: map[string]map[string]string{"test-group": {cloud.TagUID: "uid"}},
},
wantErr: true,
},
"describe groups error": {
imdsAPI: &stubIMDS{
instanceDocumentResp: &imds.GetInstanceIdentityDocumentOutput{
InstanceIdentityDocument: imds.InstanceIdentityDocument{
InstanceID: "test-instance",
},
},
},
ec2API: &stubEC2{
selfInstance: &ec2.DescribeInstancesOutput{
Reservations: []ec2types.Reservation{
{
Instances: []ec2types.Instance{
{
InstanceId: aws.String("test-instance"),
Tags: []ec2types.Tag{
{
Key: aws.String(tagName),
Value: aws.String("test-instance"),
},
{
Key: aws.String(cloud.TagUID),
Value: aws.String("uid"),
},
},
},
},
},
},
},
},
logs: &stubLogs{
describeErr: someErr,
listTags: map[string]map[string]string{"test-group": {cloud.TagUID: "uid"}},
},
wantErr: true,
},
"no matching groups": {
imdsAPI: &stubIMDS{
instanceDocumentResp: &imds.GetInstanceIdentityDocumentOutput{
InstanceIdentityDocument: imds.InstanceIdentityDocument{
InstanceID: "test-instance",
},
},
},
ec2API: &stubEC2{
selfInstance: &ec2.DescribeInstancesOutput{
Reservations: []ec2types.Reservation{
{
Instances: []ec2types.Instance{
{
InstanceId: aws.String("test-instance"),
Tags: []ec2types.Tag{
{
Key: aws.String(tagName),
Value: aws.String("test-instance"),
},
{
Key: aws.String(cloud.TagUID),
Value: aws.String("uid"),
},
},
},
},
},
},
},
},
logs: &stubLogs{
describeRes1: &logs.DescribeLogGroupsOutput{},
listTags: map[string]map[string]string{"test-group": {cloud.TagUID: "uid"}},
},
wantErr: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
l := &Logger{
api: tc.logs,
imdsAPI: tc.imdsAPI,
ec2API: tc.ec2API,
}
err := l.createStream(context.Background())
if tc.wantErr {
assert.Error(err)
return
}
assert.NoError(err)
assert.Equal(tc.wantGroup, l.groupName)
assert.Equal(tc.wantStream, l.streamName)
})
}
}
func TestLogging(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
logAPI := &stubLogs{}
l := &Logger{
api: logAPI,
interval: 1 * time.Millisecond,
clock: testclock.NewFakeClock(time.Time{}),
}
l.Disclose("msg")
l.Disclose("msg")
// no logs until we flush to the API
assert.Len(logAPI.logs, 0)
// flush
require.NoError(l.flushLogs())
assert.Len(logAPI.logs, 2)
// flushing doesn't do anything if there are no logs
require.NoError(l.flushLogs())
assert.Len(logAPI.logs, 2)
// if we flush with an incorrect sequence token,
// we should get a new sequence token and retry
logAPI.logSequenceToken = 15
l.Disclose("msg")
require.NoError(l.flushLogs())
assert.Len(logAPI.logs, 3)
logAPI.putErr = errors.New("failed")
l.Disclose("msg")
assert.Error(l.flushLogs())
}
func TestFlushLoop(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
logAPI := &stubLogs{}
clock := testclock.NewFakeClock(time.Time{})
l := &Logger{
api: logAPI,
interval: 1 * time.Second,
clock: clock,
stopCh: make(chan struct{}, 1),
}
l.Disclose("msg")
l.Disclose("msg")
l.flushLoop()
clock.Step(1 * time.Second)
require.NoError(l.Close())
assert.Len(logAPI.logs, 2)
}
func TestConcurrency(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
l := &Logger{
api: &stubLogs{},
interval: 1 * time.Second,
clock: testclock.NewFakeClock(time.Time{}),
stopCh: make(chan struct{}, 1),
}
var wg sync.WaitGroup
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer wg.Done()
l.Disclose("msg")
}()
}
wg.Wait()
assert.Len(l.logs, 100)
require.NoError(l.flushLogs())
assert.Len(l.logs, 0)
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer wg.Done()
l.Disclose("msg")
require.NoError(l.flushLogs())
}()
}
wg.Wait()
assert.Len(l.logs, 0)
}
type stubLogs struct {
createErr error
describeErr error
describeRes1 *logs.DescribeLogGroupsOutput
describeRes2 *logs.DescribeLogGroupsOutput
listTagsErr error
listTags map[string]map[string]string
putErr error
logSequenceToken int
logs []cloudwatchtypes.InputLogEvent
}
func (s *stubLogs) CreateLogStream(context.Context, *logs.CreateLogStreamInput, ...func(*logs.Options)) (*logs.CreateLogStreamOutput, error) {
return nil, s.createErr
}
func (s *stubLogs) DescribeLogGroups(_ context.Context, in *logs.DescribeLogGroupsInput, _ ...func(*logs.Options)) (*logs.DescribeLogGroupsOutput, error) {
if in.NextToken == nil {
return s.describeRes1, s.describeErr
}
return s.describeRes2, s.describeErr
}
func (s *stubLogs) ListTagsLogGroup(_ context.Context, in *logs.ListTagsLogGroupInput, _ ...func(*logs.Options)) (*logs.ListTagsLogGroupOutput, error) {
return &logs.ListTagsLogGroupOutput{Tags: s.listTags[*in.LogGroupName]}, s.listTagsErr
}
func (s *stubLogs) PutLogEvents(_ context.Context, in *logs.PutLogEventsInput, _ ...func(*logs.Options)) (*logs.PutLogEventsOutput, error) {
if s.putErr != nil {
return nil, s.putErr
}
if in.SequenceToken == nil || *in.SequenceToken == "" {
in.SequenceToken = aws.String("0")
}
gotSeq, err := strconv.Atoi(*in.SequenceToken)
if err != nil {
return nil, err
}
if gotSeq != s.logSequenceToken {
return nil, &cloudwatchtypes.InvalidSequenceTokenException{ExpectedSequenceToken: aws.String(strconv.Itoa(s.logSequenceToken))}
}
s.logs = append(s.logs, in.LogEvents...)
s.logSequenceToken++
return &logs.PutLogEventsOutput{NextSequenceToken: aws.String(strconv.Itoa(s.logSequenceToken))}, nil
}

View File

@ -7,7 +7,6 @@ go_library(
"azure.go",
"imds.go",
"interface.go",
"logger.go",
],
importpath = "github.com/edgelesssys/constellation/v2/internal/cloud/azure",
visibility = ["//:__subpackages__"],
@ -20,10 +19,8 @@ go_library(
"//internal/role",
"@com_github_azure_azure_sdk_for_go_sdk_azcore//runtime",
"@com_github_azure_azure_sdk_for_go_sdk_azidentity//:azidentity",
"@com_github_azure_azure_sdk_for_go_sdk_resourcemanager_applicationinsights_armapplicationinsights//:armapplicationinsights",
"@com_github_azure_azure_sdk_for_go_sdk_resourcemanager_compute_armcompute_v5//:armcompute",
"@com_github_azure_azure_sdk_for_go_sdk_resourcemanager_network_armnetwork_v5//:armnetwork",
"@com_github_microsoft_applicationinsights_go//appinsights",
"@io_k8s_kubernetes//pkg/util/iptables",
"@io_k8s_utils//exec",
"@org_uber_go_zap//:zap",
@ -35,7 +32,6 @@ go_test(
srcs = [
"azure_test.go",
"imds_test.go",
"logger_test.go",
],
embed = [":azure"],
deps = [
@ -44,10 +40,8 @@ go_test(
"//internal/role",
"@com_github_azure_azure_sdk_for_go_sdk_azcore//runtime",
"@com_github_azure_azure_sdk_for_go_sdk_azcore//to",
"@com_github_azure_azure_sdk_for_go_sdk_resourcemanager_applicationinsights_armapplicationinsights//:armapplicationinsights",
"@com_github_azure_azure_sdk_for_go_sdk_resourcemanager_compute_armcompute_v5//:armcompute",
"@com_github_azure_azure_sdk_for_go_sdk_resourcemanager_network_armnetwork_v5//:armnetwork",
"@com_github_azure_go_autorest_autorest_to//:to",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
"@org_golang_google_grpc//test/bufconn",

View File

@ -10,7 +10,6 @@ import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v5"
)
@ -74,9 +73,3 @@ type loadBalancerAPI interface {
NewListPager(resourceGroupName string, options *armnetwork.LoadBalancersClientListOptions,
) *runtime.Pager[armnetwork.LoadBalancersClientListResponse]
}
type applicationInsightsAPI interface {
NewListByResourceGroupPager(resourceGroupName string,
options *armapplicationinsights.ComponentsClientListByResourceGroupOptions,
) *runtime.Pager[armapplicationinsights.ComponentsClientListByResourceGroupResponse]
}

View File

@ -1,106 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package azure
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
"github.com/edgelesssys/constellation/v2/internal/cloud"
"github.com/microsoft/ApplicationInsights-Go/appinsights"
)
// Logger implements CloudLogger interface for Azure to Disclose early boot
// logs into Azure's App Insights service.
type Logger struct {
client appinsights.TelemetryClient
}
// NewLogger creates a new client to store information in Azure Application Insights
// https://github.com/Microsoft/ApplicationInsights-go
func NewLogger(ctx context.Context) (*Logger, error) {
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
return nil, fmt.Errorf("loading credentials: %w", err)
}
imdsAPI := &IMDSClient{
client: &http.Client{Transport: &http.Transport{Proxy: nil}},
}
subscriptionID, err := imdsAPI.subscriptionID(ctx)
if err != nil {
return nil, fmt.Errorf("retrieving subscription ID: %w", err)
}
appInsightAPI, err := armapplicationinsights.NewComponentsClient(subscriptionID, cred, nil)
if err != nil {
return nil, fmt.Errorf("setting up insights API client. %w", err)
}
instrumentationKey, err := getAppInsightsKey(ctx, imdsAPI, appInsightAPI)
if err != nil {
return nil, fmt.Errorf("getting app insights instrumentation key: %w", err)
}
client := appinsights.NewTelemetryClient(instrumentationKey)
name, err := imdsAPI.name(ctx)
if err != nil {
return nil, fmt.Errorf("retrieving instance name: %w", err)
}
client.Context().CommonProperties["instance-name"] = name
return &Logger{client: client}, nil
}
// Disclose stores log information in Azure Application Insights!
// Do **NOT** log sensitive information!
func (l *Logger) Disclose(msg string) {
l.client.Track(appinsights.NewTraceTelemetry(msg, appinsights.Information))
}
// Close blocks until all information are written to cloud API.
func (l *Logger) Close() error {
<-l.client.Channel().Close()
return nil
}
// getAppInsightsKey returns a instrumentation key needed to set up cloud logging on Azure.
// The key is retrieved from the resource group of the instance the function is called from.
func getAppInsightsKey(ctx context.Context, imdsAPI imdsAPI, appInsightAPI applicationInsightsAPI) (string, error) {
resourceGroup, err := imdsAPI.resourceGroup(ctx)
if err != nil {
return "", err
}
uid, err := imdsAPI.uid(ctx)
if err != nil {
return "", err
}
pager := appInsightAPI.NewListByResourceGroupPager(resourceGroup, nil)
for pager.More() {
page, err := pager.NextPage(ctx)
if err != nil {
return "", fmt.Errorf("retrieving application insights: %w", err)
}
for _, component := range page.Value {
if component == nil || component.Tags == nil ||
component.Tags[cloud.TagUID] == nil || *component.Tags[cloud.TagUID] != uid {
continue
}
if component.Properties == nil || component.Properties.InstrumentationKey == nil {
return "", errors.New("unable to get instrumentation key")
}
return *component.Properties.InstrumentationKey, nil
}
}
return "", errors.New("could not find correctly tagged application insights")
}

View File

@ -1,185 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package azure
import (
"context"
"errors"
"testing"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
"github.com/Azure/go-autorest/autorest/to"
"github.com/edgelesssys/constellation/v2/internal/cloud"
"github.com/stretchr/testify/assert"
)
func TestGetAppInsightsKey(t *testing.T) {
someErr := errors.New("failed")
goodAppInsights := armapplicationinsights.Component{
Tags: map[string]*string{
cloud.TagUID: to.StringPtr("uid"),
},
Properties: &armapplicationinsights.ComponentProperties{
InstrumentationKey: to.StringPtr("key"),
},
}
testCases := map[string]struct {
imds *stubIMDSAPI
appInsights *stubApplicationsInsightsAPI
wantKey string
wantErr bool
}{
"success": {
imds: &stubIMDSAPI{
resourceGroupVal: "resource-group",
uidVal: "uid",
},
appInsights: &stubApplicationsInsightsAPI{
pager: &stubApplicationKeyPager{list: []armapplicationinsights.Component{goodAppInsights}},
},
wantKey: "key",
},
"multiple apps": {
imds: &stubIMDSAPI{
resourceGroupVal: "resource-group",
uidVal: "uid",
},
appInsights: &stubApplicationsInsightsAPI{
pager: &stubApplicationKeyPager{list: []armapplicationinsights.Component{
{
Tags: map[string]*string{
cloud.TagUID: to.StringPtr("different-uid"),
},
Properties: &armapplicationinsights.ComponentProperties{
InstrumentationKey: to.StringPtr("different-key"),
},
},
goodAppInsights,
}},
},
wantKey: "key",
},
"missing properties": {
imds: &stubIMDSAPI{
resourceGroupVal: "resource-group",
uidVal: "uid",
},
appInsights: &stubApplicationsInsightsAPI{
pager: &stubApplicationKeyPager{list: []armapplicationinsights.Component{
{
Tags: map[string]*string{
cloud.TagUID: to.StringPtr("uid"),
},
},
}},
},
wantErr: true,
},
"no app with matching uid": {
imds: &stubIMDSAPI{
resourceGroupVal: "resource-group",
uidVal: "uid",
},
appInsights: &stubApplicationsInsightsAPI{
pager: &stubApplicationKeyPager{list: []armapplicationinsights.Component{
{
Tags: map[string]*string{
cloud.TagUID: to.StringPtr("different-uid"),
},
Properties: &armapplicationinsights.ComponentProperties{
InstrumentationKey: to.StringPtr("different-key"),
},
},
}},
},
wantErr: true,
},
"imds resource group error": {
imds: &stubIMDSAPI{
resourceGroupErr: someErr,
uidVal: "uid",
},
appInsights: &stubApplicationsInsightsAPI{
pager: &stubApplicationKeyPager{list: []armapplicationinsights.Component{goodAppInsights}},
},
wantErr: true,
},
"imds uid error": {
imds: &stubIMDSAPI{
resourceGroupVal: "resource-group",
uidErr: someErr,
},
appInsights: &stubApplicationsInsightsAPI{
pager: &stubApplicationKeyPager{list: []armapplicationinsights.Component{goodAppInsights}},
},
wantErr: true,
},
"app insights list error": {
imds: &stubIMDSAPI{
resourceGroupVal: "resource-group",
uidVal: "uid",
},
appInsights: &stubApplicationsInsightsAPI{
pager: &stubApplicationKeyPager{fetchErr: someErr},
},
wantErr: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
key, err := getAppInsightsKey(context.Background(), tc.imds, tc.appInsights)
if tc.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tc.wantKey, key)
}
})
}
}
type stubApplicationKeyPager struct {
list []armapplicationinsights.Component
fetchErr error
more bool
}
func (p *stubApplicationKeyPager) moreFunc() func(armapplicationinsights.ComponentsClientListByResourceGroupResponse) bool {
return func(armapplicationinsights.ComponentsClientListByResourceGroupResponse) bool {
return p.more
}
}
func (p *stubApplicationKeyPager) fetcherFunc() func(context.Context, *armapplicationinsights.ComponentsClientListByResourceGroupResponse,
) (armapplicationinsights.ComponentsClientListByResourceGroupResponse, error) {
return func(context.Context, *armapplicationinsights.ComponentsClientListByResourceGroupResponse) (armapplicationinsights.ComponentsClientListByResourceGroupResponse, error) {
page := make([]*armapplicationinsights.Component, len(p.list))
for i := range p.list {
page[i] = &p.list[i]
}
return armapplicationinsights.ComponentsClientListByResourceGroupResponse{
ComponentListResult: armapplicationinsights.ComponentListResult{
Value: page,
},
}, p.fetchErr
}
}
type stubApplicationsInsightsAPI struct {
pager *stubApplicationKeyPager
}
func (a *stubApplicationsInsightsAPI) NewListByResourceGroupPager(_ string, _ *armapplicationinsights.ComponentsClientListByResourceGroupOptions,
) *runtime.Pager[armapplicationinsights.ComponentsClientListByResourceGroupResponse] {
return runtime.NewPager(runtime.PagingHandler[armapplicationinsights.ComponentsClientListByResourceGroupResponse]{
More: a.pager.moreFunc(),
Fetcher: a.pager.fetcherFunc(),
})
}

View File

@ -6,7 +6,6 @@ go_library(
srcs = [
"gcp.go",
"interface.go",
"logger.go",
"wrappers.go",
],
importpath = "github.com/edgelesssys/constellation/v2/internal/cloud/gcp",
@ -20,7 +19,6 @@ go_library(
"@com_google_cloud_go_compute//apiv1",
"@com_google_cloud_go_compute//apiv1/computepb",
"@com_google_cloud_go_compute_metadata//:metadata",
"@com_google_cloud_go_logging//:logging",
"@org_golang_google_api//iterator",
"@org_golang_google_protobuf//proto",
],

View File

@ -1,54 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package gcp
import (
"context"
"fmt"
"log"
"cloud.google.com/go/compute/metadata"
"cloud.google.com/go/logging"
)
// Logger logs to GCP cloud logging. Do not use to log sensitive information.
type Logger struct {
client *logging.Client
logger *log.Logger
}
// NewLogger creates a new Cloud Logger for GCP.
// https://cloud.google.com/logging/docs/setup/go
func NewLogger(ctx context.Context, logName string) (*Logger, error) {
projectID, err := metadata.NewClient(nil).ProjectID()
if err != nil {
return nil, fmt.Errorf("retrieving project ID from imds: %w", err)
}
client, err := logging.NewClient(ctx, projectID)
if err != nil {
return nil, err
}
logger := client.Logger(logName).StandardLogger(logging.Info)
return &Logger{
client: client,
logger: logger,
}, nil
}
// Disclose stores log information in GCP Cloud Logging! Do **NOT** log sensitive
// information!
func (l *Logger) Disclose(msg string) {
l.logger.Println(msg)
}
// Close waits for all buffer to be written.
func (l *Logger) Close() error {
return l.client.Close()
}

View File

@ -2,10 +2,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "qemu",
srcs = [
"logger.go",
"qemu.go",
],
srcs = ["qemu.go"],
importpath = "github.com/edgelesssys/constellation/v2/internal/cloud/qemu",
visibility = ["//:__subpackages__"],
deps = [

View File

@ -1,44 +0,0 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package qemu
import (
"context"
"net/http"
"net/url"
"strings"
)
// Logger is a Cloud Logger for QEMU.
type Logger struct{}
// NewLogger creates a new Cloud Logger for QEMU.
func NewLogger() *Logger {
return &Logger{}
}
// Disclose writes log information to QEMU's cloud log.
// This is done by sending a POST request to the QEMU's metadata endpoint.
func (l *Logger) Disclose(msg string) {
url := &url.URL{
Scheme: "http",
Host: qemuMetadataEndpoint,
Path: "/log",
}
req, _ := http.NewRequestWithContext(context.Background(), http.MethodPost, url.String(), strings.NewReader(msg))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err == nil {
defer resp.Body.Close()
}
}
// Close is a no-op.
func (l *Logger) Close() error {
return nil
}

View File

@ -162,12 +162,6 @@ resource "aws_security_group" "security_group" {
}
resource "aws_cloudwatch_log_group" "log_group" {
name = local.name
retention_in_days = 30
tags = local.tags
}
module "load_balancer_targets" {
for_each = { for port in local.load_balancer_ports : port.name => port }
source = "./modules/load_balancer_target"

View File

@ -77,14 +77,6 @@ resource "azurerm_attestation_provider" "attestation_provider" {
}
}
resource "azurerm_application_insights" "insights" {
name = local.name
location = var.location
resource_group_name = var.resource_group
application_type = "other"
tags = local.tags
}
resource "azurerm_public_ip" "loadbalancer_ip" {
count = var.internal_load_balancer ? 0 : 1
name = "${local.name}-lb"

View File

@ -80,7 +80,6 @@ resource "google_compute_subnetwork" "vpc_subnetwork" {
]
}
resource "google_compute_subnetwork" "proxy_subnet" {
count = var.internal_load_balancer ? 1 : 0
name = "${local.name}-proxy"
@ -128,7 +127,6 @@ resource "google_compute_firewall" "firewall_external" {
var.internal_load_balancer ? [22] : [],
])
}
}
resource "google_compute_firewall" "firewall_internal_nodes" {
@ -155,7 +153,6 @@ resource "google_compute_firewall" "firewall_internal_pods" {
allow { protocol = "icmp" }
}
module "instance_group" {
source = "./modules/instance_group"
for_each = var.node_groups

View File

@ -30,6 +30,7 @@ resource "random_password" "init_secret" {
special = true
override_special = "_%@"
}
resource "docker_image" "qemu_metadata" {
name = var.metadata_api_image
keep_locally = true