Showing posts with label .Net. Show all posts
Showing posts with label .Net. Show all posts

Friday, April 28, 2023

AWS Secret Manager for application running on Amazon EC2 instances

Using AWS Secret Manager

 

 

Introduction

This technical document describes the approach of using AWS Secrets Manager to securely manage secrets and credentials for application running on Amazon EC2 instances. The document outlines the steps to configure the necessary infrastructure components, including AWS Secrets Manager, AWS Identity and Access Management (IAM), and Azure DevOps.

Solution defined in the document is generic and can be applied to programs planning to implement AWS secret manager in their respective projects leveraging Azure Devops

Approach

The approach described in this document consists of the following steps:

·        Configure AWS Secrets Manager to store secrets

·        Create an IAM policy for the EC2 instance to access Secrets Manager

·        Configure Azure DevOps to fetch secrets from Secrets Manager

·        Pass secrets to the .NET Core application using environment variables or application config

 

Detailed Solution

1.      Configure AWS Secrets Manager to store secrets

·        Create a new secret in AWS Secrets Manager for each environment (dev, qa, prod) that the application uses

o   Non Prod

§  Dev_Secrets

§  QA_secrets

§  Qualif_Secrets

o   Prod Secrets

§  Prod_Secrets

·        Alternately we can also store all environment secrets per service.

Note - If you have a small number of services and environments, storing all environment secrets per service may simplify secret management and reduce the risk of misconfigurations. However, if you have a large number of services and environments or require more flexibility, storing secrets per environment may be a better approach.

If you are expecting to develop multiple micro services hence it’s better to go for storing secrets per environment

 

·        Store all the secrets for each environment as a key-value pairs in JSON format

 

2.      Create an IAM policy for the EC2 instance to access Secrets Manager

·        Create IAM Users for prod and non-prod environments

o   Generate AWS access key and secret access key

o   Access Type – Programmatic Access

·        Attach Policy SecretsManagerRead to Users created in step 2

·        If we push the secret to App.config then this is not required

o   Attach IAM roles for EC2 instances for applications to access Secret manager at runtime

o   Attach the appropriate AWS managed policy that grants permissions to access Secrets Manager

 

3.      Configure Azure DevOps to fetch secrets from Secrets Manager

·        Create a new service connection in Azure DevOps for AWS, using the IAM credentials for accessing Secrets Manager

o   Navigate to the "Project Settings" in Azure DevOps and click on "Service connections".

o   Click on "New service connection" and select "AWS".

o   Follow the prompts to enter your AWS access key and secret access key, as well as the region where your AWS resources are located.

4.      Create a new pipeline variable in Azure DevOps for the secret name:

o   In the Azure DevOps pipeline, define variable (e.g., "EnvironmentSecret") and set the value to the name of the secret that you want to fetch from AWS Secrets Manager.

§  E.g: EnvironmentSecret = Dev_Secrets’ – to Identify Build environment

§  Refer secret name created in Step 1

 

5.      Add an Azure DevOps task to fetch the secret:

 

o   In Azure DevOps pipeline, add a task that fetches the secret from AWS Secrets Manager.

o   aws secretsmanager get-secret-value --secret-id $(EnvironmentSecret) --query SecretString --output text

o   aws secretsmanager get-secret-value --secret-id EnvironmentSecret --query SecretString

 

6.      Pass the secret value to your .NET Core application

There are multiple options to store the secret . This can be evaluated and agreed upon

 

o   Use Environment Variable in EC2

§  Via Azure DevOps task and update environment variable in EC2

§  MySecretName ={ SecretString }

 

(OR)

o   Use configuration files

§  Via Azure App Service Deploy task to deploy the configuration file to the Azure App Service that hosts your .NET Core application

 

o   Store the Output secret value from the previous step into a Key value pair

o   Create new Azure DevOps task called "Azure App Service Settings"

(OR)

o   Store the secrets in Secure Files in Azure Pipelines and push it into appconfig file

Go to Pipelines > Library > Secure files

 

7.      Aplication code

.NET Core application to retrieve the value of "MySecretName":

 

string secretValue = Environment.GetEnvironmentVariable("MySecretName");

 

 

 

References

https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch

https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/azure-app-service-settings-v1?view=azure-pipelines&viewFallbackFrom=azure-devops

https://aws.amazon.com/blogs/modernizing-with-aws/how-to-load-net-configuration-from-aws-secrets-manager/

 

 

 

Tuesday, October 19, 2021

IIS Application app pool getting crashed intermittently

I was debugging another interesting issue  where after doing a specific business transaction, Application pool getting stopped and service become unavailable.

Application logs doesn’t give much details

2021-10-08 19:48:25.8085 4.10.191 INFO Beginning Startup...

2021-10-08 19:48:25.8505 4.10.191 INFO CORS configuration found, allowing the following Origins: 

2021-10-08 19:48:25.8505 4.10.191 INFO Allowed Origin: https://xxx.hostname..local

2021-10-08 19:48:25.8505 4.10.191 INFO Applying CORS Configurations

2021-10-08 19:48:25.8505 4.10.191 WARN `Auth Configuration not found, defaulting to IWA

2021-10-08 19:48:25.8505 4.10.191 INFO Configuring for Intergrated Windows Authentication

2021-10-08 19:48:28.0246 4.10.191 INFO Authorization.Extension: Start parsing : "D:\inetpub\wwwroot \1.0\bin\Authorization.rules".

2021-10-08 19:48:28.1396 4.10.191 INFO Authorization Role Definitions have been created.

2021-10-08 19:48:28.1396 4.10.191 INFO Authorization.Extension: Successfully finished parsing : "D:\inetpub\wwwroot\1.0\bin\Authorization.rules".

2021-10-08 19:48:31.2079 4.10.191 INFO Startup Completed.

Another Http exception was also observed as below 

Message: Request is not available in this context
Stack:
[HelperMethodFrame]
System.Web.HttpContext.get_Request()
System.Web.HttpContextWrapper.get_Request()
NLog.Web.Internal.HttpContextExtensions.TryGetRequest(System.Web.HttpContextBase)
NLog.Web.LayoutRenderers.AspNetRequestValueLayoutRenderer.DoAppend(System.Text.StringBuilder, NLog.LogEventInfo)
NLog.LayoutRenderers.LayoutRenderer.RenderAppendBuilder(NLog.LogEventInfo, System.Text.StringBuilder)
NLog.Layouts.SimpleLayout.RenderAllRenderers(NLog.LogEventInfo, System.Text.StringBuilder)
NLog.Layouts.Layout.RenderAppendBuilder(NLog.LogEventInfo, System.Text.StringBuilder, Boolean)
NLog.Layouts.SimpleLayout.PrecalculateBuilder(NLog.LogEventInfo, System.Text.StringBuilder)
NLog.Targets.Target.PrecalculateVolatileLayoutsConcurrent(NLog.LogEventInfo)
NLog.Targets.Wrappers.AsyncTargetWrapper.Write(NLog.Common.AsyncLogEventInfo)
NLog.Targets.Wrappers.AsyncTargetWrapper.WriteAsyncThreadSafe(NLog.Common.AsyncLogEventInfo)
NLog.Targets.Target.WriteAsyncLogEvent(NLog.Common.AsyncLogEventInfo)
NLog.LoggerImpl.WriteToTargetWithFilterChain(NLog.Targets.Target, NLog.Filters.FilterResult, NLog.LogEventInfo, NLog.Common.AsyncContinuation)
NLog.LoggerImpl.Write(System.Type, NLog.Internal.TargetWithFilterChain, NLog.LogEventInfo, NLog.LogFactory)
NLog.Logger.Trace(System.String)
System.Web.HttpApplication.InitModulesCommon()
System.Web.HttpApplication.InitInternal(System.Web.HttpContext, System.Web.HttpApplicationState, System.Reflection.MethodInfo[])
System.Web.HttpApplicationFactory.GetNormalApplicationInstance(System.Web.HttpContext)
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)
System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)
System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)
DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)

 

Events logs

Events logs has below entries and it doesn’t have stack trace to debug

  •         A process serving application pool name.Psh' suffered a fatal communication error with the Windows Process Activation Service. The process id was '53196'. The data field contains the error number.
  •        Application pool name.Psh ' is being automatically disabled due to a series of failures in the process(es) serving that application pool.
  •         Application popup: w3wp.exe - System Error : A new guard page for the stack cannot be created.

 

To debug, I have configured debugdiag to capture memory dumps on crash and found couple of exceptions on the threads

  45   60 1ef18 00000214ce10fff0  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  46   62 7884 00000214cdf937a0  1029220 Cooperative 00000214B811CB00:00000214B811D8D0 00000214af95f900 0     Ukn (Threadpool Worker)

  47   47 8b50 00000214ce0f28c0  8029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Completion Port)

  48   65 17114 00000214ce10a1f0  8029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Completion Port)

  49   63 7bd4 00000214cdbafd90  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  50   61 1598 00000214ce0ab520  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  51   58 16c04 00000214ce0f20f0  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  52   57 1314c 00000214cdfaf0e0  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  53   55 1ecfc 00000214cdfad060  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  54   54 12004 00000214ce10c130  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  55   53 128f0 00000214ce0f3860  1029220 Preemptive  00000214B811A580:00000214B811B8D0 00000214af95f900 0     Ukn (Threadpool Worker) System.Web.HttpException 00000214b811a498

  56   52 c7a0 00000214ce0fa0d0  1029220 Preemptive  00000214B80E8168:00000214B80E98D0 00000214af95f900 1     Ukn (Threadpool Worker) System.StackOverflowException 00000214afc91158

  57   48 e110 00000214ce0c0950  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  58   34 7a4c 00000214ce0f0980  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

  59   39 3450 00000214ce0f1150  1029220 Preemptive  0000000000000000:0000000000000000 00000214af874010 0     Ukn (Threadpool Worker)

 

from the dump, Its clear that app pool crashed due to System.StackOverflowException on thread 56

 

Review the stack trace of thread 56 gives hint that automapper causing stack overflow


RootCause

Application has circular reference in its classes which are used on the workflow because of this when user attempt to perform type casting via automapper, stack is getting filled up.

Solution to the problem is to Avoid type conversion via auto mapper instead converting types using manual mapping.

 


Tuesday, October 12, 2021

Fiddler improves Service Response times?

One of the development teams approached me with an interesting issue. The issue description states the response time of a service call is faster by 100% when ever Fiddler is running.  I was requested to suggest if the same performance can be achieved without fiddler.

I took some Network traces  at the client with and with out fiddler and found some interesting observations

Without fiddler, Only 2 TCP connections were used between the client and the server



With Fiddler - there were 4 active parallel TCP connections resulting  faster response time




With the data it is clear more the parallel connections the better the response time. With the issue identified solution is even simpler

By default, we can create only two simultaneous connections to an HTTP server.   This can be increased to avoid a backlog of requests during times of very high transaction volume. It can be done in many ways as given in the link below

https://developer.cybersource.com/library/documentation/dev_guides/Simple_Order_API_Clients/html/Topics/Setting_the_Connection_Limit.htm


Monday, September 20, 2021

Dynamic Compression in IIS

 Dynamic compression doesn't work by default in IIS and there are few config changes that are needed to be done for it to working. Please refer the below steps to implement the same

Enable Compression in IIS application

 Prerequisite: Dynamic content compression module should be installed. If it is not installed, please install. It can be done using Server Manager.

Do the followings for Webclient and other sites related to the application.

·       Enable Dynamic Compression at site level.

 


·       Traverse Configuration Editor to check and configure appropriate compression settings.


·       Traverse to “system.webServer/httpCompression” section.

 








·      
Click on dynamic Types and add application/json mimeType if missing. That is responsible to compress api level responses. Add this in Webclient and API site levels.


 





·       Save and restart the app pool.

·       Verify in the client side that dynamic compression is working or not. It should have “Content-Encoding: gzip” in Response Headers.





Claim Based Authorization

  1.      Claim Based Authorization ·         Token Validation: As requests come into the Ocelot API Gateway, the first step is to validat...