dotnet / dotnet-docker

Docker images for .NET and the .NET Tools.
https://hub.docker.com/_/microsoft-dotnet
MIT License
4.48k stars 1.94k forks source link

Provide Documentation on Securing ASP.NET Core Containers #940

Open RehanSaeed opened 5 years ago

RehanSaeed commented 5 years ago

I've discovered that you can run an ASP.NET Core image with a read-only file system but this requires you to turn off debugging and profiling support because otherwise you get an error. Full sample here.

docker run --rm --read-only -it -p 8000:80 -e COMPlus_EnableDiagnostics=0 my-asp-app

There are also a myriad of settings we can use in Kubernetes. Here is a sample Pod yaml:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: gcr.io/google-samples/node-hello:1.0
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        add: ["NET_ADMIN", "SYS_TIME"]

As a linux noob, I'd really like more information and guidance on runAsUser, fsGroup and capabilities in particular. It would be ideal if a basic set of capabilities could be provided to get a hello world app running but also some description of what needs to be added to get additional features.

MichaelSimons commented 5 years ago

@richlander - There are some good suggestions here. Is this something better covered by the docs or a sample here?

RehanSaeed commented 5 years ago

I'd just like to add that running a read-only file system does not currently work if you are buffering requests in ASP.NET Core. If you are transferring JSON in ASP.NET Core, then JSON.NET apparently requires buffering but the new JSON API's in .NET Core 3 will apparently solve this issue. More details in https://github.com/RehanSaeed/ReadOnlyDockerTest/issues/1 and https://github.com/aspnet/AspNetCore/issues/3704.

RehanSaeed commented 5 years ago

Also adding PID Limiting to this list which is a new feature in Kubernetes 1.14 but is currently beta. That feature will probably go live in 1.15.

MichaelSimons commented 5 years ago

@glennc - Is this something you are interested in documenting from the ASP.NET perspective if something doesn't already exist?

MichaelSimons commented 5 years ago

Ping @glennc

MichaelSimons commented 5 years ago

@blowdart will be taking on this per conversation started by @richlander. Feel free to move the issue to an ASP.NET or other repo if there is a more appropriate place to track this work.

\<Edit> The topic of providing guidance still being discussed. No decisions have been made yet.

blowdart commented 5 years ago

Please don't move this to the aspnet repo, as the vast majority of this is not an aspnet question and I will simply move it back.

To speak to the one asp.net part of this;

"you can run an ASP.NET Core image with a read-only file system"

@RehanSaeed you are frankly lucky in what you tested. ASP.NET Core will start to buffer requests to disk when under memory pressure because not doing so is a huge DoS vector. ASP.NET does not support running on read only file systems. Just because it gets "fixed" in JSON doesn't mean it will get fixed in the request pipeline. It's currently not a goal.

MichaelSimons commented 5 years ago

@blowdart - sure - I have no intentions to move it myself. I am just trying to get @RehanSaeed question answered and a decision if we are going to provide additional guidance.

hbiarge commented 4 years ago

Are there any decision taken on this? Any advise over those security settings?

Thanks!

baoduy commented 3 years ago

My app using Service Bus Client and after applied the Security Context I got this issue on AKS. Please the solution to fix the issue if anyone have. Thank you so much

crit: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to start Kestrel.
      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.SocketConnectionListener.<Bind>g__BindSocket|13_0(<>c__DisplayClass13_0& )
         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)
         at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass29_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)
         at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(AddressBindContext context)
         at Microsoft.AspNetCore.Server.Kestrel.Core.AnyIPListenOptions.BindAsync(AddressBindContext context)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IEnumerable`1 listenOptions, AddressBindContext context)
         at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
info: Balance.Infras.Events.BalanceSubscriptionClient[0]
      Handling TransferStatusChanged
fail: Balance.Infras.Events.BalanceSubscriptionClient[0]
      Service bus client on balance-transfer-sub failed to handle message call back Cannot access a disposed object.
      Object name: 'IServiceProvider'. ; action UserCallback on endpoint sg-dev-backbonebus-trans.servicebus.windows.net and entity transfer-v1-tp/Subscriptions/balance-transfer-sub
      System.ObjectDisposedException: Cannot access a disposed object.
      Object name: 'IServiceProvider'.
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
         at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
         at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
         at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.CreateScope(IServiceProvider provider)
         at Balance.Infras.Events.BalanceSubscriptionClient.<RegisterSubscriptionClientMessageHandler>b__17_0(Message message, CancellationToken token) in /app/Balance/Balance.Infras/Events/BalanceSubscriptionClient.cs:line 114
         at Microsoft.Azure.ServiceBus.MessageReceivePump.MessageDispatchTask(Message message)
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.SocketConnectionListener.<Bind>g__BindSocket|13_0(<>c__DisplayClass13_0& )
   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)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass29_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)
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.AnyIPListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IEnumerable`1 listenOptions, AddressBindContext context)
   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 Balance.Api.Program.Main(String[] args) in /app/Balance/Balance.Api/Program.cs:line 57
   at Balance.Api.Program.<Main>(String[] args)
RehanSaeed commented 3 years ago

There is a nice writeup here. Any chance this could be turned into proper docs?

https://techcommunity.microsoft.com/t5/azure-developer-community-blog/hardening-an-asp-net-container-running-on-kubernetes/ba-p/2542224

mthalman commented 1 year ago

@davidfowl - Does there exist any documentation that might help this request of having guidance for securely configuring ASP.NET Core in container scenarios?

davidfowl commented 1 year ago

cc @richlander

danmoseley commented 1 year ago

@RehanSaeed you are frankly lucky in what you tested. ASP.NET Core will start to buffer requests to disk when under memory pressure because not doing so is a huge DoS vector. ASP.NET does not support running on read only file systems. Just because it gets "fixed" in JSON doesn't mean it will get fixed in the request pipeline. It's currently not a goal.

Is the question assuming that /tmp (or $ASPNETCORE_TEMP) is not writeable? or only that the deployment directory is not writeable?

benjaminlhai commented 11 months ago

This needs more attention - diagnostics / profiling should not be mutually exclusive with read only root filesystem. At least allow the usage of a custom directory/mount a tmpfs or similar volume for collection and set that folder via environment vars. Unless this is an option that is documented somewhere? I couldn't find anything valuable (other than this issue)

esbenbjerre commented 6 months ago

@richlander can you confirm whether or not it is considered safe to run a .NET 7/8 app on a read-only file system assuming ASPNETCORE_TEMP points to a writeable folder?

davidfowl commented 6 months ago

It should be yes.

richlander commented 6 months ago

I have another blog post planned on prod deployments. I can include this aspect.