microsoft / azure-container-apps

Roadmap and issues for Azure Container Apps
MIT License
370 stars 29 forks source link

Restrict inbound HTTP traffic by IP address #243

Closed cosminstirbu closed 1 year ago

cosminstirbu commented 2 years ago

Hello,

We're looking at moving away from App Services and using Container Apps.

One feature that we're currently using from App Services is to only allow inbound traffic from the IP address of our API Management instance.

How would we achieve this with Container Apps?

Can it be done on an app by app basis? Or will the rules be applicable at the environment level?

Thank you, Cosmin

torosent commented 2 years ago

I would recommend creating the Container Environment internal only and then connecting APIM to a different subnet. That will guarantee that your env is locked down without public IPs. https://docs.microsoft.com/en-us/azure/container-apps/vnet-custom-internal?tabs=bash&pivots=azure-portal Something like this: https://techcommunity.microsoft.com/t5/apps-on-azure-blog/connected-microservices-with-azure-container-apps/ba-p/3072158

cosminstirbu commented 2 years ago

Your recommendation would work.

In our organization however we have a central API Management instance where different teams plug in their APIs (I agree that it can be argued it's a single point of failure, but that's a different conversation).

The existing API Management instance doesn't use a VNET and at this point, integrating it with one would require coordination with multiple teams (since there's a change it will also involve some downtime).

Ideally we'd like something as simple as the Networking section on the App Service.

JoaoBrandao commented 2 years ago

Hi @cosminstirbu,

there are three options available when comes network in Container Apps:

  1. Limited to Container Apps Environment - This will set automatically a VNET for you - can work depending on your use cases
  2. Accepting traffic from anywhere - Container Apps is open to the world - avoid this option if possible
  3. Limited to VNET - this must be set when you create the environment for the first time.

According to your information, you want to limit the access to your Container Apps by only allowing access to your API Management and routing the traffic from Azure API Management into Container Apps.

The best option and the only one that I am seeing is to have a shared subnet between API Management and Container App. Since you have multiple teams using API management, why you don't setup your own API Gateway instead of using a shared instance?

Diagram using VNET vnet-container-app

cosminstirbu commented 2 years ago

Hi @JoaoBrandao

The reason why we use a central API Management gateway is to have a single "landing-page" for all APIs exposed by our organization to the outside world.

This allows us to provide a smoother developer experience in terms of discoverability of our APIs, rather than having multiple instances of API Management and therefore also multiple developer portals.

JoaoBrandao commented 2 years ago

You can try to use this approach:

But since you have this limitation of VNET, I would suggest checking API Management options but looks like it is mostly impossible to make what you want in terms of network.

JarkoDubbeldam commented 2 years ago

I've also been looking for a way to whitelist IP-addresses into container apps. I did find a possible solution:

Deploy the container environment into a VNet with external LB. Then use a Network Security Group on the subnet where the environment lives to lock down incoming traffic. In my case this was a specific IP-cidr, but it looks like this could also be done using service tags (ApiManagement). Combining this with the header solution mentioned above (to lock it down further to your ApiManagement specifically) might work.

I wonder what experts think about this?

cosminstirbu commented 2 years ago

Another thing worth mentioning is that in order to use a VNET on API Management you need to be on the Premium tier, which costs $2,795.17 vs $686.71 (Standard tier).

NullQubit commented 2 years ago

One of the appeals of using container apps is that we don't have to manage all these resources (internal vnets, subnets, gateways) so it would be nice if we could just restrict access to APIM IP. For the moment we went with the secret key in header approach, although it is a security concern since container apps are still exposed to public network traffic.

snobu commented 2 years ago

I second @NullQubit on his concerns. Adding a lot more complexity and moving parts just to restrict source IP access is not ideal and may hinder adoption in favor of raw AKS. I am working on a project as we speak that stays on AKS for this simple reason, adding Application Gateway + internal managed environment is too much unnecessary added complexity for basic IP filtering.

If you could expose a property to filter in traffic at the ingress point, it would be enough for most scenarios.

E.g. -

"ingress": { 
  "traffic": [
    {
         "allowedSourceIp": [
           "21.19.4.0/24",
           "91.4.0.0/16"
         ]
    }
  ]
}

I'm sure Envoy already supports this so it's just a matter of passing the right config snippet. 401 or 403 HTTP responses are both perfectly acceptable.

Additionally, exposing Azure Portal blade UI for this property under Ingress will significantly raise the production value of the service.

Think of all the gov agencies that are mandated to restrict source IP traffic, on top of authentication. I don't know if this is a thing in US as well, but it's everywhere in Europe.

kendallroden commented 2 years ago

Thank you all for this thoughtful feedback and discussion. I have taken note on the feature request and we will be working to document the various networking approaches. I've change the name to narrow the scope of this issue for now as we have multiple on a similar topic

ahmelsayed commented 1 year ago

This can be done using api 2022-06-01-preview

{
  "properties": {
    "configuration": {
      "ingress": {
        "ipSecurityRestrictions": [
          {
            "ipAddressRange": "21.19.4.0/24",
            "action": "Allow"
          },
          {
            "ipAddressRange": "91.4.0.0/16",
            "action": "Allow"
          }
        ]
      }
    }
  }
}
ilmax commented 1 year ago

That's awesome 😎

onionhammer commented 1 year ago

Does this work with front door FDID headers and service tags?

ahmelsayed commented 1 year ago

It doesn't, xff headers are not trusted either. This is strictly CIDR for the IP address of the client atm.

deokgonkim commented 1 year ago

I created azure container apps using az cli as follows

az containerapp create --resource-group $RESOURCE_GROUP --yaml deploy.yml \
--name $CONTAINER_APPS_NAME

And here is snippet of yaml file.

configuration:
  activeRevisionsMode: Multiple
  ingress:
    allowInsecure: false
    ipSecurityRestrictions:
    - action: "Allow"
      name: "Allow office"
      ipAddressRange: "[myip]/32"
    external: true
    targetPort: 5011

But it doesn't work, I don't know how to force to use API Version 2022-06-01-preview or later. I am new to azure and azure cli.

ilmax commented 1 year ago

I created azure container apps using az cli as follows

az containerapp create --resource-group $RESOURCE_GROUP --yaml deploy.yml \
--name $CONTAINER_APPS_NAME

And here is snippet of yaml file.

configuration:
  activeRevisionsMode: Multiple
  ingress:
    allowInsecure: false
    ipSecurityRestrictions:
    - action: "Allow"
      name: "Allow office"
      ipAddressRange: "[myip]/32"
    external: true
    targetPort: 5011

But it doesn't work, I don't know how to force to use API Version 2022-06-01-preview or later. I am new to azure and azure cli.

I think you can force the api version using either bicep or ARM temaplates, with the azure cli it's a bit more complicated since the cli is a wrapper around the azure apis. If you don't really want to use any of the aforementioned options, you can still somehow use the azure cli but it requires a bit more effort. First you have to turn debug logging on using the --debug flag and copy and the request body and add the additional parameters and then use the az rest (see here) command to hit the api version you want.

Hope this helps

christle commented 1 year ago

If I put the IP restriction, like an API Management IP to our container apps it works as expected, except for one thing. A Dapr Service Invoke is blocked from the IP Restriction. I think this shouldn't be the case. And I have no IP range to put in there. I've tested the outbound IP address of the source ACA, but it doesn't work. Any ideas?

kendallroden commented 1 year ago

@christle - thanks for letting us know. Will notify the team and keep you posted. Do you mind creating a separate issue for this?

christle commented 1 year ago

Done, #527

ahmelsayed commented 1 year ago

Closing as complete

03eltond commented 9 months ago

It would be nice if this worked with ipv6 as well. For a use case, we use Cloudflare, and as such we want to limit incoming traffic to the IP ranges provided by CF, which includes ipv6. There are workarounds, but it's unfortunate to have to do so when this feature ALMOST satisfies that need.