Home > Software design >  How to resolve "Permission denied" on .NET6 in EKS?
How to resolve "Permission denied" on .NET6 in EKS?

Time:07-04

I am new to AWS EKS but I am trying to deploy a sample WebApp using .NET6. However I get the following exception when I check the pod logs

    Microsoft.AspNetCore.DataProtection.Repositories.EphemeralXmlRepository[50]
      Using an in-memory repository. Keys will not be persisted to storage.
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[59]
      Neither user profile nor HKLM registry available. Using an ephemeral key repository. Protected data will be unavailable when application exits.
dbug: Microsoft.Extensions.Hosting.Internal.Host[1]
      Hosting starting
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {bc16347e-42d1-4598-adb3-06afbbb81c7a} may be persisted to storage in unencrypted form.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Overriding address(es) 'http://*:8080'. Binding to endpoints defined via IConfiguration and/or UseKestrel() instead.
Unhandled exception. System.Net.Sockets.SocketException (13): Permission denied
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions.CreateDefaultBoundListenSocket(EndPoint endpoint)      
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind()
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(EndPoint endPoint, ConnectionDelegate connectionDelegate, EndpointConfig endpointConfig, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass30_0`1.<<StartAsync>g__OnBind|0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(AddressBindContext context, CancellationToken cancellationToken)   
   at Microsoft.AspNetCore.Server.Kestrel.Core.AnyIPListenOptions.BindAsync(AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.BindAsync(AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IEnumerable`1 listenOptions, AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at Microsoft.AspNetCore.Builder.WebApplication.Run(String url)
   at Program.<Main>$(String[] args) in /src/SampleWebApp/Program.cs:line 24

It seems that the Kestrel cannot start but I don't know why. I have changed the Program.cs like this:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.WebHost.UseKestrel(opts =>
{
    opts.ListenAnyIP(8080);
});
var app = builder.Build();

because I have read that ports below 1024 are not allowed in EKS. This did not do the trick. After that I have found the following article: https://techcommunity.microsoft.com/t5/azure-developer-community-blog/hardening-an-asp-net-container-running-on-kubernetes/ba-p/2542224 so I have applied all on my Dockerfile and helm chart. Unfortunately this did not fix the issue as well.

Currently I have this as a Dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base

WORKDIR /app
EXPOSE 8080

ENV ASPNETCORE_URLS=http://*:8080
ENV COMPlus_EnableDiagnostics=0

RUN addgroup --group friendlygroupname --gid 2000 \
&& adduser \    
    --uid 1000 \
    --gid 2000 \
    "friendlyusername" 

RUN chown friendlyusername:friendlygroupname  /app /tmp
USER friendlyusername:friendlygroupname 

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["SampleWebApp/SampleWebApp.csproj", "SampleWebApp/"]
RUN dotnet restore "SampleWebApp/SampleWebApp.csproj"
COPY . .
WORKDIR "/src/SampleWebApp"
RUN dotnet build "SampleWebApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "SampleWebApp.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

ENTRYPOINT ["dotnet", "SampleWebApp.dll"]

and my template for the helm chart of the deployment is:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "test-app.fullname" . }}
  labels:
    {{- include "test-app.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "test-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "test-app.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "test-app.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          env:          
            {{- range .Values.env }}
            - name: {{ .name }}
              value: {{ .value | quote }}
            {{- end }}
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}

where I have the following values:

test-app:
    replicatCount: 1

    image:
        repository: 751825048932.dkr.ecr.eu-central-1.amazonaws.com/sample-web-app
        pullPolicy: IfNotPresent
        tag: "latest"

    env:
        - name: "COMPlus_EnableDiagnostics"
          value: "0"
        - name: "ASPNETCORE_URLS"
          value: "http://*:8080"
        - name: "ASPNETCORE_ENVIRONMENT"
          value: "Development"
        - name: "Logging__LogLevel__Default"
          value: "Debug"

    podSecurityContext: 
        runAsNonRoot: true
        runAsUser: 1000
        runAsGroup: 2000

    securityContext: 
        runAsNonRoot: true 
        runAsUser: 1000
        runAsGroup: 2000
        allowPrivilegeEscalation: false
        privileged: false
        readOnlyRootFilesystem: true
        capabilities:
            drop:
                - all

    service:
        type: "ClusterIP"
        port: 8080

    ingress:
        enabled: true
        annotations:
            nginx.ingress.kubernetes.io/rewrite-target: "/"
        hosts:
          - host: chart-example.local
            paths: 
            - path: "/my-test-app"

    autoscaling:
        enabled: false
        
    serviceAccount:
        create: false

Obviously I am missing something or doing something wrong. Some help would be much appreciated because it seems I am stuck with this one. I get "Permission denied" or "Failed to create CoreCLR, HRESULT: 0x80004005".

Thanks in advance!

CodePudding user response:

The issues is solved. Everything described is correct beside the Dockerfile. The definition of user and group should be made later. Now the Dockerfile looks like:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base

WORKDIR /app
EXPOSE 8080

ENV ASPNETCORE_URLS=http://*:8080
ENV COMPlus_EnableDiagnostics=0

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["SampleWebApp/SampleWebApp.csproj", "SampleWebApp/"]
RUN dotnet restore "SampleWebApp/SampleWebApp.csproj"
COPY . .
WORKDIR "/src/SampleWebApp"
RUN dotnet build "SampleWebApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "SampleWebApp.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

RUN addgroup --group friendlygroupname --gid 2000 \
&& adduser \    
    --uid 1000 \
    --gid 2000 \
    "friendlyusername" 

RUN chown friendlyusername:friendlygroupname  /app /tmp
USER friendlyusername:friendlygroupname 

ENTRYPOINT ["dotnet", "SampleWebApp.dll"]
  • Related