You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AWS VPC Container Network Interface (CNI) for Kubernetes has an inherent limit on number of pods per instance, due to using one ENI per pod per instance. The workaround is to use Calico CNI. The Calico CNI can be deployed in EKS to run alongside the VPC CNI, providing Kubernetes Network Policies support.
Allows cascading of policies, better expressing ownership, admin delegation
Adds new capabilities on top of traditional namespaces
Delegate subnamespace creation without cluster privileges
Cascading policies, secrets, configmaps
Trusted labels for policies
Security
Securing Authentication
Use an admission controller as an extra layer of authZ validation.
Make sure that users are assigned proper roles. Assign namespace-specific permissions instead of cluster-wide privileges to minimize exposure.
Securing Kubernetes Core Components
AKS allows setting a cluster as either public or private. It may be necessary to build your AKS/EKS cluster to be “private” so that it is not accessible by routable IPs (by default).
Network access to the Kubernetes components API server (control plane), etcd (persistent storage database), kubelet agent, kubedns must use an encrypted connection. Ensure that Kubernetes clusters have end-to-end TLS enabled.
Lock down all unsecured API server ports. Use a bastion host, configure VPN, or use an internal network to access the nodes and other infrastructure resources.
Limit exposure of Kubernetes Dashboard. Disable public access via the internet. Ensure the Dashboard Service Account is not open and accessible to users. Configure the login page and enable RBAC.
Securing Images
Use private container registries and tagged container images, keeping tagged images immutable
Continuously scan Docker container images that run your application for CVE using scanning tools.
Kubernetes can be configured to send all deployment requests to a dynamic admission controller for approval before they go to the Kubernetes scheduler, which is responsible for placing pods on nodes. If the deployment fails the controller’s configured tests, the pod won’t get run at all.
Container runtimes start by adding a securityContext to every deployment that allocates a non-root user and disables privilege escalation. You can enforce these limitations in your cluster by using PodSecurityPolicies.
Make sure you give each application in your cluster its own Kubernetes service account.
Securing Pods
Network Access
By default, all pods can communicate with one another. Every Pod gets its own IP address. This means you do not need to explicitly create links between Pods and you almost never need to deal with mapping container ports to host ports. To lock down access you can either use a Network Policy or use Service Mesh. The entities that a Pod can communicate with are identified through a combination of the following 3 identifiers:
Other pods that are allowed (exception: a pod cannot block access to itself)
Namespaces that are allowed
IP blocks (exception: traffic to and from the node where a Pod is running is always allowed, regardless of the IP address of the Pod or the node)
Within Azure there are two main approaches to Network Policies.
Azure’s own implementation, called Azure Network Policies. (Supports Linux) supported by Azure support team
Calico Network Policies, an open-source network and network security solution founded by Tigera. (Supports Linux and Windows) and Kubenet CNI
User Access
Limit the number of users who can create pods and try not to use unknown or unmaintained libraries.
Securing Namespaces
Use different namespaces for different environments like (dev/test/stage/prod).
Securing Resources
By default, all resources are created with unbounded CPU and memory limits. To prevent “noisy neighbors” and potential DoS (denial of service) situations, do not let containers run without an upper bound on resources. You can assign resource quota policies at the namespace level, in order to limit overconsumption of the CPU and memory resources a pod is allowed to consume.
Securing Kubernetes Instances
Protect the Identity and Access Management (IAM) credentials of your nodes’ IAM Instance Role. If you don’t use kube2iam or kiam, which both work by intercepting calls to the metadata endpoint and issuing limited credentials back to the pod based on your configuration, install the Calico CNI so you can add a Network Policy to block access to the metadata IP, 169.254.169.254.
$ kubectl cluster-info
Kubernetes control plane is running at https://aaaaaaaaaaaaaaaaaaaaaaa.gr7.us-east-2.eks.amazonaws.com
CoreDNS is running at https://aaaaaaaaaaaaaaaaaaaaaaa.gr7.us-east-2.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
metrics-server is running at https://aaaaaaaaaaaaaaaaaaaa.gr7.us-east-2.eks.amazonaws.com/api/v1/namespaces/kube-system/services/https:metrics-server:https/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Create a namespace per deployment group
By default, kubernetes will use the default namespace. This becomes difficult to manage over time
as more and more components are piled together. Best practice is to create a new namespace specific
to what you deploy.
Due to security limitations in Kubernetes, you should create a unique namespace for every one of your
applications. Otherwise you will not be able to control some of the interactions between applications
in the same namespace.
You can add hierarchical information to your namespaces, such as your Product, Subproduct, and Environment.
You might not have a Subproduct, but it can also be a general term for any grouping of services, like a database and web server.
It is recommended not to include an organization or team name, as when those names inevitably change as organizations get
reorganized, the names will become inaccurate.
Create a product/subproduct/environment/application namespace. You can do this manually in kubectl:
When you create an object, without specifying the namespace, it will be created in current Namespace which, if not changed manually to a custom Namespace, is default Namespace.
You can specify a namespace for an object in two ways: by either using namespace field in specification YAML file for object, or using namespace flag in command line.
Kubernetes namespaces must be an RFC 1123 label (MUST consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character).
You can connect to Kubernetes services running in a specific namespace using the fully-qualified DNS address:
<service name>.<namespace name>.svc.cluster.local
Network policies may limit access to services between namespaces.
Create a namespace
kubectl create namespace test1
Get namespaces
kubectl get namespaces -o yaml
kubectl get namespace test1 -o yaml
All Kubernetes clusters have inherent static limitations
No more than 110 pods per node
No more than 5000 nodes
No more than 150000 total pods
No more than 300000 total containers
Security within Namespaces is DANGEROUS
Service Accounts and Secrets are freely usable within a namespace. Anyone with permission to deploy a Pod in a namespace can use any Service Account and any Secret.
Namespaces only isolate the control plane, not the data plane. Anything within a namespace can attack the cluster. Use Sandboxing (gVisor, Kata) to protect the data plane.
This page will document some of the information most useful when developing apps to run on Kubernetes.
Liveness, Readiness, & Startup Probes
Your application should have a liveness, readiness, and startup probe configured before you deploy it to production. This ensures that Kubernetes won’t send it traffic until the application (and its dependencies) are ready to start serving traffic.
Your application should specify the amount of resources it needs to run. This has a couple purposes:
If you have a process that ends up taking up all the CPU available, it can impact other apps. CPU limits prevent one CPU-hungry app from limiting the entire cluster.
If you have a process with runaway memory growth, memory won’t be available for other apps, and it’s going to die eventually when all memory is exhausted.
Requests: The requests specification is used at pod placement time: Kubernetes will look for a node that has both enough CPU and memory according to the requests configuration.
Limits: This is enforced at runtime. If a container exceeds the limits, Kubernetes will try to stop it. For CPU, it will simply curb the usage so a container typically can't exceed its limit capacity ; it won't be killed, just won't be able to use more CPU. If a container exceeds its memory limits, it could be terminated.
Considerations:
If you under-size these limits, your application may end up running out of memory or running slowly.
If you over-size these limits, yours or someone else’s app may not deploy correctly if the Kubernetes cluster doesn’t have enough resources to schedule all the apps with their reserved limits. You may not notice a problem unless you are watching the deployment status of your app, and problems may only show themselves after apps re-start themselves when they fail.
Your Operations Engineers may impose resource quotas at the Namespace level to prevent apps from taking up too many resources (or too few). Nobody wants to be limited, but we do need to make sure all the apps can run.
spec:
template:
spec:
containers:
- name: demo-app
# ... add this line to never cache the image
imagePullPolicy: Always
Restrict network access to only what needs to access it. The following allows all access to the pod:
# pod network policies are a different resource
# add these lines at the end of deployment.yml
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector:
matchLabels:
app: demo-app
ingress:
- {}
egress:
- {}
policyTypes:
- Ingress
- Egress
Restrict the security context of the container. You should restrict this as much as is needed for your app to still work. This example just makes the container filesystem read-only and sets a high user/group ID:
spec:
template:
spec:
containers:
- name: demo-app
# add a security context for the container
securityContext:
runAsUser: 10001
runAsGroup: 10001
readOnlyRootFilesystem: true