Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cost monitoring with kubecost and AMP #154

Merged
merged 30 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2dc5de2
Cost monitoring pattern
Howlla Feb 14, 2024
8bd2c55
adds KubeCostExtensionAddOn
arunvthangaraj Mar 4, 2024
cc9bb35
adds managed nodegroup
arunvthangaraj Mar 6, 2024
d05c131
disable kubecost prometheus node exporter
arunvthangaraj Mar 8, 2024
67e08a4
adds cognito auth to kubecost dashboard
arunvthangaraj Mar 12, 2024
8271fb0
Added helm chart values for sigv4
Howlla Mar 18, 2024
4d38bcf
pushing version update
Howlla Mar 20, 2024
bafdaba
typo fix
Howlla Mar 20, 2024
dc0cb7d
change to oss pattern
Howlla Mar 21, 2024
47da964
remove extra bin file
Howlla Mar 21, 2024
fc9b667
working otel collector
Howlla Mar 21, 2024
17b4143
working otel collector
Howlla Mar 21, 2024
6f858b4
random text
Howlla Mar 21, 2024
a7d2847
fix comments from reviewer
Howlla Mar 21, 2024
869f92c
fix CI build issues
Howlla Mar 21, 2024
3bd9623
fix CI build issues
Howlla Mar 21, 2024
00eb109
fix comments
Howlla Mar 22, 2024
3df0b78
added documentation
Howlla Apr 1, 2024
e13bf46
Merge branch 'main' into cost_mon
Howlla Apr 7, 2024
605d526
make recommended changes
Howlla Apr 7, 2024
702c723
update architecture diagram
Howlla Apr 23, 2024
0c144ee
final commit
Howlla Apr 29, 2024
05c0311
revert cdk.json
Howlla Apr 29, 2024
f8cce81
Merge branch 'aws-observability:main' into cost_mon
Howlla Apr 29, 2024
dfbcb01
fix GH action failing due to cdk.json missing values
Howlla Apr 29, 2024
8df084a
moving cognito stack to common folder
Howlla Apr 30, 2024
83f3486
moving cognito stack to common folder
Howlla Apr 30, 2024
a59c136
rename incorrect folder typo
Howlla Apr 30, 2024
d6a3094
rename incorrect folder typo
Howlla Apr 30, 2024
3537896
update deploy and destroy commands
Howlla Apr 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bin/single-new-eks-awsnative-cost-monitoring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import SingleNewEksCostMonitoringPattern from '../lib/single-new-eks-cost-monitoring-pattern';
import { configureApp } from '../lib/common/construct-utils';
Howlla marked this conversation as resolved.
Show resolved Hide resolved

const app = configureApp();

new SingleNewEksCostMonitoringPattern(app, "single-new-eks-awsnative-cost");
11 changes: 11 additions & 0 deletions bin/single-new-eks-cost-monitoring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { configureApp, errorHandler } from '../lib/common/construct-utils';
import SingleNewEksCostMonitoringPattern from '../lib/single-new-eks-cost-monitoring-pattern';

const app = configureApp();

new SingleNewEksCostMonitoringPattern()
.buildAsync(app, 'single-new-eks-cost-monitoring')
.catch((e) => {
errorHandler(app, "Secure Ingress Auth pattern is not setup due to missing secrets for ArgoCD admin pwd. \
Howlla marked this conversation as resolved.
Show resolved Hide resolved
See Secure Ingress Auth in the readme for instructions", e);
});
11 changes: 11 additions & 0 deletions lib/common/resources/otel-collector-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ spec:
external_labels:
cluster: "{{clusterName}}"
scrape_configs:
- job_name: kubecost
Howlla marked this conversation as resolved.
Show resolved Hide resolved
honor_labels: true
scrape_interval: 1m
scrape_timeout: 10s
metrics_path: /metrics
scheme: http
dns_sd_configs:
- names:
- dashboard.kubecost.avt.eks.aws.dev
type: 'A'
port: 9003
{{ start enableAdotMetricsCollectionJob}}
- job_name: otel-collector-metrics
scrape_interval: 10s
Expand Down
129 changes: 129 additions & 0 deletions lib/single-new-eks-cost-monitoring-pattern/cognito-idp-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import * as cdk from 'aws-cdk-lib';
import * as blueprints from '@aws-quickstart/eks-blueprints';
import { Construct } from 'constructs';
import * as cognito from 'aws-cdk-lib/aws-cognito';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';

export default class CognitoIdpStack extends cdk.Stack {

public readonly userPoolOut: cognito.UserPool;
public readonly userPoolClientOut: cognito.UserPoolClient;
public readonly userPoolDomainOut: cognito.UserPoolDomain;

constructor(scope: Construct, id: string, subDomain: string, props?: cdk.StackProps) {
super(scope, id, props);

const lambdaExecutionRole = new iam.Role(this, 'Lambda Execution Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

lambdaExecutionRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole"));
lambdaExecutionRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMReadOnlyAccess"));

const authChallengeFn = new lambda.Function(this, 'authChallengeFn', {
runtime: lambda.Runtime.PYTHON_3_12,
code: lambda.Code.fromAsset('./lib/single-new-eks-cost-monitoring-pattern/lambda'),
handler: 'lambda_function.lambda_handler',
role: lambdaExecutionRole,
environment: {
"ALLOWED_DOMAINS_LIST": blueprints.utils.valueFromContext(scope, "allowed.domains.list", "example.com")
}
});


// Cognito User Pool
const userPool = new cognito.UserPool(this, 'CognitoIDPUserPool', {
userPoolName: 'CognitoIDPUserPool',
selfSignUpEnabled: true,
signInAliases: {
email: true,
username: true
},
standardAttributes: {
email: {
mutable: true,
required: true
},
givenName: {
mutable: true,
required: true
},
familyName: {
mutable: true,
required: true
}
},
lambdaTriggers: {
preSignUp: authChallengeFn,
preAuthentication: authChallengeFn,
},
});


// Output the User Pool ID

this.userPoolOut = userPool;

new cdk.CfnOutput(this, 'CognitoIDPUserPoolOut', {
value: userPool.userPoolId,
exportName: 'CognitoIDPUserPoolId'
});

new cdk.CfnOutput(this, 'CognitoIDPUserPoolArnOut', {
value: userPool.userPoolArn,
exportName: 'CognitoIDPUserPoolArn'
});


// We will ask the IDP to redirect back to our domain's index page
const redirectUri = `https://${subDomain}/oauth2/idpresponse`;

// Configure the user pool client application
const userPoolClient = new cognito.UserPoolClient(this, 'CognitoAppClient', {
userPool,
authFlows: {
userPassword: true
},
oAuth: {
flows: {
authorizationCodeGrant: true
},
scopes: [
cognito.OAuthScope.OPENID
],
callbackUrls: [redirectUri]
// TODO - What about logoutUrls?
},
generateSecret: true,
userPoolClientName: 'Web',
supportedIdentityProviders: [cognito.UserPoolClientIdentityProvider.COGNITO]
});

// Output the User Pool App Client ID
this.userPoolClientOut = userPoolClient;

new cdk.CfnOutput(this, 'CognitoIDPUserPoolClientOut', {
value: userPoolClient.userPoolClientId,
exportName: 'CognitoIDPUserPoolClientId'
});

// Add the domain to the user pool
const randomText = (Math.random() + 1).toString(36).substring(7);
const userPoolDomain = userPool.addDomain('CognitoDomain', {
cognitoDomain: {
domainPrefix: `my-cdk-blueprint-${randomText}`,
},
});

// Output the User Pool App Client ID

this.userPoolDomainOut = userPoolDomain;

new cdk.CfnOutput(this, 'CognitoIDPUserPoolDomainOut', {
value: userPoolDomain.domainName,
exportName: 'CognitoIDPUserPoolDomain'
});

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import 'source-map-support/register';
import * as blueprints from '@aws-quickstart/eks-blueprints';
import * as eks from "aws-cdk-lib/aws-eks";
import { ManagedPolicy } from "aws-cdk-lib/aws-iam";
import { Construct } from 'constructs';
import { createNamespace, dependable } from '@aws-quickstart/eks-blueprints/dist/utils';
elamaran11 marked this conversation as resolved.
Show resolved Hide resolved

export class GrafanaOperatorSecretAddon implements blueprints.ClusterAddOn {
id?: string | undefined;
@dependable(blueprints.addons.ExternalsSecretsAddOn.name, blueprints.addons.GrafanaOperatorAddon.name)
deploy(clusterInfo: blueprints.ClusterInfo): void | Promise<Construct> {
const cluster = clusterInfo.cluster;

const policyRead = ManagedPolicy.fromAwsManagedPolicyName("AmazonPrometheusQueryAccess");
const policyWrite = ManagedPolicy.fromAwsManagedPolicyName("AmazonPrometheusRemoteWriteAccess");

const serviceAccount1 = cluster.addServiceAccount("kubecost-cost-analyzer-amp", {
name: "kubecost-cost-analyzer-amp",
namespace: "kubecost"
});


serviceAccount1.role.addManagedPolicy(policyRead);
serviceAccount1.role.addManagedPolicy(policyWrite);

const serviceAccount2 = cluster.addServiceAccount("kubecost-prometheus-server-amp", {
name: "kubecost-prometheus-server-amp",
namespace: "kubecost"
});

serviceAccount2.role.addManagedPolicy(policyRead);
serviceAccount2.role.addManagedPolicy(policyWrite);

const namespace = createNamespace("kubecost",cluster);

serviceAccount1.node.addDependency(namespace);
serviceAccount2.node.addDependency(namespace);

const secretStore = new eks.KubernetesManifest(clusterInfo.cluster.stack, "ClusterSecretStore", {
cluster: cluster,
manifest: [
{
apiVersion: "external-secrets.io/v1beta1",
kind: "ClusterSecretStore",
metadata: {
name: "ssm-parameter-store",
namespace: "default"
},
spec: {
provider: {
aws: {
service: "ParameterStore",
region: clusterInfo.cluster.stack.region,
auth: {
jwt: {
serviceAccountRef: {
name: "external-secrets-sa",
namespace: "external-secrets",
},
},
},
},
},
},
},
],
});

const externalSecret = new eks.KubernetesManifest(clusterInfo.cluster.stack, "ExternalSecret", {
cluster: cluster,
manifest: [
{
apiVersion: "external-secrets.io/v1beta1",
kind: "ExternalSecret",
metadata: {
name: "external-grafana-admin-credentials",
namespace: "grafana-operator"
},
spec: {
secretStoreRef: {
name: "ssm-parameter-store",
kind: "ClusterSecretStore",
},
target: {
name: "grafana-admin-credentials"
},
data: [
{
secretKey: "GF_SECURITY_ADMIN_APIKEY",
remoteRef: {
key: "/cdk-accelerator/grafana-api-key"
},
},
],
},
},
],
});
externalSecret.node.addDependency(secretStore);
return Promise.resolve(secretStore);
}
}
Loading
Loading