2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-06-03 05:55:18 -04:00
|
|
|
package azure
|
|
|
|
|
|
|
|
import (
|
2022-06-10 07:18:30 -04:00
|
|
|
"context"
|
|
|
|
"errors"
|
2022-08-29 05:54:30 -04:00
|
|
|
"fmt"
|
2022-11-15 03:08:18 -05:00
|
|
|
"net/http"
|
2022-06-10 07:18:30 -04:00
|
|
|
|
2022-11-15 03:08:18 -05:00
|
|
|
"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"
|
2022-06-03 05:55:18 -04:00
|
|
|
"github.com/microsoft/ApplicationInsights-Go/appinsights"
|
|
|
|
)
|
|
|
|
|
2022-11-09 09:57:54 -05:00
|
|
|
// Logger implements CloudLogger interface for Azure to Disclose early boot
|
|
|
|
// logs into Azure's App Insights service.
|
2022-06-03 05:55:18 -04:00
|
|
|
type Logger struct {
|
|
|
|
client appinsights.TelemetryClient
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewLogger creates a new client to store information in Azure Application Insights
|
|
|
|
// https://github.com/Microsoft/ApplicationInsights-go
|
2022-11-15 03:08:18 -05:00
|
|
|
func NewLogger(ctx context.Context) (*Logger, error) {
|
|
|
|
cred, err := azidentity.NewDefaultAzureCredential(nil)
|
2022-06-10 07:18:30 -04:00
|
|
|
if err != nil {
|
2022-11-15 03:08:18 -05:00
|
|
|
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)
|
2022-06-10 07:18:30 -04:00
|
|
|
}
|
|
|
|
|
2022-11-15 03:08:18 -05:00
|
|
|
instrumentationKey, err := getAppInsightsKey(ctx, imdsAPI, appInsightAPI)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("getting app insights instrumentation key: %w", err)
|
2022-06-10 07:18:30 -04:00
|
|
|
}
|
2022-08-01 06:32:28 -04:00
|
|
|
|
2022-11-15 03:08:18 -05:00
|
|
|
client := appinsights.NewTelemetryClient(instrumentationKey)
|
2022-08-29 05:54:30 -04:00
|
|
|
|
2022-11-15 03:08:18 -05:00
|
|
|
name, err := imdsAPI.name(ctx)
|
2022-08-01 06:32:28 -04:00
|
|
|
if err != nil {
|
2022-11-15 03:08:18 -05:00
|
|
|
return nil, fmt.Errorf("retrieving instance name: %w", err)
|
2022-08-01 06:32:28 -04:00
|
|
|
}
|
2022-11-15 03:08:18 -05:00
|
|
|
client.Context().CommonProperties["instance-name"] = name
|
2022-06-10 07:18:30 -04:00
|
|
|
|
2022-08-29 05:54:30 -04:00
|
|
|
return &Logger{client: client}, nil
|
2022-06-03 05:55:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2022-11-15 03:08:18 -05:00
|
|
|
|
|
|
|
// 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")
|
|
|
|
}
|