Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions user-management/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/

**/net8.0/*
**/tmp/*

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
Expand Down
8 changes: 7 additions & 1 deletion user-management/Stickerlandia.UserManagement.sln
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{FC9DDF76-8
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stickerlandia.UserManagement.Agnostic", "src\Stickerlandia.UserManagement.Agnostic\Stickerlandia.UserManagement.Agnostic.csproj", "{295E8315-2CD2-4CD8-B7F4-21EF587B74A9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stickerlandia.UserManagement.Lambda", "src\Stickerlandia.UserManagement.Lambda\src\Stickerlandia.UserManagement.Lambda\Stickerlandia.UserManagement.Lambda.csproj", "{5C770F92-B6E7-4270-A041-A32F385DA6C4}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stickerlandia.UserManagement.Lambda", "src\Stickerlandia.UserManagement.Lambda\Stickerlandia.UserManagement.Lambda.csproj", "{5C770F92-B6E7-4270-A041-A32F385DA6C4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driving", "Driving", "{924749FC-98D5-40A6-8F4B-BA9BFDEDDEC3}"
EndProject
Expand All @@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stickerlandia.UserManagemen
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stickerlandia.UserManagement.MigrationService", "src\Stickerlandia.UserManagement.MigrationService\Stickerlandia.UserManagement.MigrationService.csproj", "{91536DB3-CBA5-44DE-943C-76F8577793FE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserManagementService", "infra\aws\src\UserManagementService.csproj", "{57FBF8EA-3559-45A5-ACE1-823B2225E370}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -106,6 +108,10 @@ Global
{91536DB3-CBA5-44DE-943C-76F8577793FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91536DB3-CBA5-44DE-943C-76F8577793FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91536DB3-CBA5-44DE-943C-76F8577793FE}.Release|Any CPU.Build.0 = Release|Any CPU
{57FBF8EA-3559-45A5-ACE1-823B2225E370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57FBF8EA-3559-45A5-ACE1-823B2225E370}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57FBF8EA-3559-45A5-ACE1-823B2225E370}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57FBF8EA-3559-45A5-ACE1-823B2225E370}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4DDC795B-2EA4-4123-B631-F0D8CAA99BA6} = {FE220876-2B87-4095-8BD2-039049503C72}
Expand Down
14 changes: 14 additions & 0 deletions user-management/infra/aws/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Welcome to your CDK C# project!

This is a blank project for CDK development with C#.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

It uses the [.NET CLI](https://docs.microsoft.com/dotnet/articles/core/) to compile and execute your project.

## Useful commands

* `dotnet build src` compile this app
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk synth` emits the synthesized CloudFormation template
94 changes: 94 additions & 0 deletions user-management/infra/aws/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"app": "dotnet run --project src/UserManagementService.csproj",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"src/*/obj",
"src/*/bin",
"src/*.sln",
"src/*/GlobalSuppressions.cs",
"src/*/*.csproj"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
"@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false,
"@aws-cdk/aws-ecs:disableEcsImdsBlocking": true,
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
"@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true,
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true,
"@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true,
"@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true,
"@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true,
"@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true,
"@aws-cdk/core:enableAdditionalMetadataCollection": true,
"@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": false,
"@aws-cdk/aws-s3:setUniqueReplicationRoleName": true,
"@aws-cdk/aws-events:requireEventBusPolicySid": true,
"@aws-cdk/core:aspectPrioritiesMutating": true,
"@aws-cdk/aws-dynamodb:retainTableReplica": true,
"@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": true,
"@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": true,
"@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": true,
"@aws-cdk/aws-s3:publicAccessBlockedByDefault": true
}
}
1 change: 1 addition & 0 deletions user-management/infra/aws/src/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0026:Possible unassigned object created by 'new'", Justification = "Constructs add themselves to the scope in which they are created")]
96 changes: 96 additions & 0 deletions user-management/infra/aws/src/InstrumentedFunction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2024 Datadog, Inc.

using Amazon.CDK;
using Amazon.CDK.AWS.IAM;
using Amazon.CDK.AWS.Lambda;
using Amazon.CDK.AWS.Lambda.DotNet;
using Amazon.CDK.AWS.Logs;
using Amazon.CDK.AWS.SecretsManager;
using Constructs;
using Environment = System.Environment;

namespace UserManagementService;

public record FunctionProps(
SharedProps Shared,
string FunctionName,
string ProjectPath,
string Handler,
Dictionary<string, string> EnvironmentVariables);

public class InstrumentedFunction : Construct
{
public IFunction Function { get; private set; }

public InstrumentedFunction(Construct scope, string id, FunctionProps props) : base(scope, id)
{
if (props.Handler.Length > 128)
throw new Exception(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Code Quality Violation

do not throw generic exceptions (...read more)

Exceptions should be specific to the application to help points the exact issue. For these reasons, generic exceptions should not be used and we should instead favor specific exception types.

View in Datadog  Leave us feedback  Documentation

"Function handler cannot be greater than 128 chars. https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler");
var functionName = $"{props.Shared.ServiceName}-{props.FunctionName}-{props.Shared.Env}";

if (functionName.Length > 64)
{
var extraCharacters = functionName.Length - 64;

functionName =
$"{props.Shared.ServiceName}-{props.FunctionName.Substring(0, props.FunctionName.Length - extraCharacters)}-{props.Shared.Env}";
}

var defaultEnvironmentVariables = new Dictionary<string, string>()
{
{ "POWERTOOLS_SERVICE_NAME", props.Shared.ServiceName },
{ "POWERTOOLS_LOG_LEVEL", "DEBUG" },
{ "AWS_LAMBDA_EXEC_WRAPPER", "/opt/datadog_wrapper" },
{ "DD_SITE", Environment.GetEnvironmentVariable("DD_SITE") },
{ "DD_ENV", props.Shared.Env },
{ "ENV", props.Shared.Env },
{ "DD_VERSION", props.Shared.Version },
{ "DD_SERVICE", props.Shared.ServiceName },
{ "DD_API_KEY_SECRET_ARN", props.Shared.DDApiKeySecret.SecretArn },
{ "DD_CAPTURE_LAMBDA_PAYLOAD", "true" },
{ "DOMAIN", props.Shared.Domain },
{ "TEAM", props.Shared.Team }
};

Function = new DotNetFunction(this, id,
new DotNetFunctionProps
{
ProjectDir = props.ProjectPath,
Handler = props.Handler,
MemorySize = 1024,
Timeout = Duration.Seconds(29),
Runtime = Runtime.DOTNET_8,
Environment = defaultEnvironmentVariables.Union(props.EnvironmentVariables)
.ToDictionary(x => x.Key, x => x.Value),
Architecture = Architecture.ARM_64,
FunctionName = functionName,
LogRetention = RetentionDays.ONE_DAY,
Layers =
[
LayerVersion.FromLayerVersionArn(this, "DDExtension",
$"arn:aws:lambda:{Environment.GetEnvironmentVariable("AWS_REGION") ?? "us-east-1"}:464622532012:layer:Datadog-Extension-ARM:80"),
LayerVersion.FromLayerVersionArn(this, "DDTrace",
$"arn:aws:lambda:{Environment.GetEnvironmentVariable("AWS_REGION") ?? "us-east-1"}:464622532012:layer:dd-trace-dotnet-ARM:20")
]
});

// The Datadog extension sends log data to Datadog using the telemetry API, disabling CloudWatch prevents 'double paying' for logs
if (Environment.GetEnvironmentVariable("ENABLE_CLOUDWATCH_LOGS") != "Y")
Function.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps()
{
Resources = new[] { "arn:aws:logs:*:*:*" },
Actions = new[]
{
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
},
Effect = Effect.DENY
}));

props.Shared.DDApiKeySecret.GrantRead(Function);
}
}
16 changes: 16 additions & 0 deletions user-management/infra/aws/src/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Amazon.CDK;

namespace UserManagementService
{
sealed class Program

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Quality Violation

Suggested change
sealed class Program
sealed static class Program
class could be made static (...read more)

This rule states that a class should be declared as static if it only contains static members. Declaring a class as static indicates that it cannot be instantiated or extended and that all its members are static. This provides a clear signal to other developers that this class is not meant to be used as an object.

What the rule detects

The rule detects if all members are static . If they are, the rule recommends to declare the class static.

How to fix the issue?

Declare the class static by adding the static keyword to its declaration.

View in Datadog  Leave us feedback  Documentation

{
public static void Main(string[] args)
{
var app = new App();
var userManagementServiceStack = new UserManagementServiceStack(app, "UserManagementServiceStack", new StackProps());
userManagementServiceStack.Tags.SetTag("team", "users");
userManagementServiceStack.Tags.SetTag("domain", "users");
app.Synth();
}
}
}
9 changes: 9 additions & 0 deletions user-management/infra/aws/src/SharedProps.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2024 Datadog, Inc.

using Amazon.CDK.AWS.SecretsManager;

namespace UserManagementService;

public record SharedProps(string ServiceName, string Env, string Version, string Team, string Domain, ISecret DDApiKeySecret, string DDSite);
19 changes: 19 additions & 0 deletions user-management/infra/aws/src/UserManagementService.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<!-- Roll forward to future major versions of the netcoreapp as needed -->
<RollForward>Major</RollForward>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<!-- CDK Construct Library dependencies -->
<PackageReference Include="Amazon.CDK.Lib" Version="2.200.1" />
<PackageReference Include="Constructs" Version="10.4.2" />
<PackageReference Include="Amazon.CDK.AWS.Lambda.DotNet" Version="0.0.6" />
<PackageReference Include="Amazon.Jsii.Analyzers" Version="1.112.0" PrivateAssets="all" />
</ItemGroup>

</Project>
Loading
Loading