1"use strict";(self.webpackChunktigera_docs=self.webpackChunktigera_docs||[]).push([["434"],{38016:function(e,t,o){o.r(t),o.d(t,{frontMatter:()=>i,toc:()=>c,default:()=>h,metadata:()=>n,assets:()=>a,contentTitle:()=>r});var n=JSON.parse('{"id":"network-policy/hosts/kubernetes-nodes","title":"Protect Kubernetes nodes","description":"Protect Kubernetes nodes with host endpoints managed by Calico.","source":"@site/calico_versioned_docs/version-3.28/network-policy/hosts/kubernetes-nodes.mdx","sourceDirName":"network-policy/hosts","slug":"/network-policy/hosts/kubernetes-nodes","permalink":"/calico/3.28/network-policy/hosts/kubernetes-nodes","draft":false,"unlisted":false,"editUrl":"https://github.com/tigera/docs/edit/main/calico_versioned_docs/version-3.28/network-policy/hosts/kubernetes-nodes.mdx","tags":[],"version":"3.28","frontMatter":{"description":"Protect Kubernetes nodes with host endpoints managed by Calico."},"sidebar":"calicoSidebar","previous":{"title":"Protect hosts and VMs","permalink":"/calico/3.28/network-policy/hosts/protect-hosts"},"next":{"title":"Protect hosts tutorial","permalink":"/calico/3.28/network-policy/hosts/protect-hosts-tutorial"}}'),s=o(37937),l=o(17869);let i={description:"Protect Kubernetes nodes with host endpoints managed by Calico."},r="Protect Kubernetes nodes",a={},c=[{value:"Big picture",id:"big-picture",level:2},{value:"Value",id:"value",level:2},{value:"Concepts",id:"concepts",level:2},{value:"Host endpoints",id:"host-endpoints",level:2},{value:"Automatic host endpoints",id:"automatic-host-endpoints",level:2},{value:"Before you begin...",id:"before-you-begin",level:2},{value:"How to",id:"how-to",level:2},{value:"Enable automatic host endpoints",id:"enable-automatic-host-endpoints",level:3},{value:"Apply network policy to automatic host endpoints",id:"apply-network-policy-to-automatic-host-endpoints",level:3},{value:"Tutorial",id:"tutorial",level:2},{value:"Additional resources",id:"additional-resources",level:2}];function d(e){let t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"protect-kubernetes-nodes",children:"Protect Kubernetes nodes"})}),"\n",(0,s.jsx)(t.h2,{id:"big-picture",children:"Big picture"}),"\n",(0,s.jsx)(t.p,{children:"Secure Kubernetes nodes with host endpoints managed by Calico."}),"\n",(0,s.jsx)(t.h2,{id:"value",children:"Value"}),"\n",(0,s.jsx)(t.p,{children:"Calico can automatically create host endpoints for your Kubernetes nodes. This means Calico can manage the lifecycle of host endpoints as your cluster evolves, ensuring nodes are always protected by policy."}),"\n",(0,s.jsx)(t.h2,{id:"concepts",children:"Concepts"}),"\n",(0,s.jsx)(t.h2,{id:"host-endpoints",children:"Host endpoints"}),"\n",(0,s.jsx)(t.p,{children:"Each host has one or more network interfaces that it uses to communicate externally. You can represent these interfaces in Calico using host endpoints and then use network policy to secure them."}),"\n",(0,s.jsx)(t.p,{children:"Calico host endpoints can have labels, and they work the same as labels on workload endpoints. The network policy rules can apply to both workload and host endpoints using label selectors."}),"\n",(0,s.jsxs)(t.p,{children:["Automatic host endpoints secure all of the host's interfaces (i.e. in Linux, all the interfaces in the host network namespace). They are created by setting ",(0,s.jsx)(t.code,{children:'interfaceName: "*"'}),"."]}),"\n",(0,s.jsx)(t.h2,{id:"automatic-host-endpoints",children:"Automatic host endpoints"}),"\n",(0,s.jsx)(t.p,{children:"Calico creates a wildcard host endpoint for each node, with the host endpoint containing the same labels and IP addresses as its corresponding node.\nCalico will ensure these managed host endpoints maintain the same labels and IP addresses as its node by periodic syncs.\nThis means that policy targeting these automatic host endpoints will function correctly with the policy put in place to select those nodes, even if over time the node's IPs or labels change."}),"\n",(0,s.jsxs)(t.p,{children:["Automatic host endpoints are differentiated from other host endpoints by the label ",(0,s.jsx)(t.code,{children:"projectcalico.org/created-by: calico-kube-controllers"}),".\nEnable or disable automatic host endpoints by configuring the default KubeControllersConfiguration resource."]}),"\n",(0,s.jsx)(t.h2,{id:"before-you-begin",children:"Before you begin..."}),"\n",(0,s.jsxs)(t.p,{children:["Have a running Calico cluster with ",(0,s.jsx)(t.code,{children:"calicoctl"})," installed."]}),"\n",(0,s.jsx)(t.h2,{id:"how-to",children:"How to"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#enable-automatic-host-endpoints",children:"Enable automatic host endpoints"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#apply-network-policy-to-automatic-host-endpoints",children:"Apply network policy to automatic host endpoints"})}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"enable-automatic-host-endpoints",children:"Enable automatic host endpoints"}),"\n",(0,s.jsxs)(t.p,{children:["To enable automatic host endpoints, edit the default KubeControllersConfiguration instance, and set ",(0,s.jsx)(t.code,{children:"spec.controllers.node.hostEndpoint.autoCreate"})," to ",(0,s.jsx)(t.code,{children:"true"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:'calicoctl patch kubecontrollersconfiguration default --patch=\'{"spec": {"controllers": {"node": {"hostEndpoint": {"autoCreate": "Enabled"}}}}}\'\n'})}),"\n",(0,s.jsx)(t.p,{children:"If successful, host endpoints are created for each of your cluster's nodes:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"calicoctl get heps -owide\n"})}),"\n",(0,s.jsx)(t.p,{children:"The output may look similar to this:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{children:"calicoctl get heps -owide\nNAME NODE INTERFACE IPS PROFILES\nip-172-16-101-147.us-west-2.compute.internal-auto-hep ip-172-16-101-147.us-west-2.compute.internal * 172.16.101.147,192.168.228.128 projectcalico-default-allow\nip-172-16-101-54.us-west-2.compute.internal-auto-hep ip-172-16-101-54.us-west-2.compute.internal * 172.16.101.54,192.168.107.128 projectcalico-default-allow\nip-172-16-101-79.us-west-2.compute.internal-auto-hep ip-172-16-101-79.us-west-2.compute.internal * 172.16.101.79,192.168.91.64 projectcalico-default-allow\nip-172-16-101-9.us-west-2.compute.internal-auto-hep ip-172-16-101-9.us-west-2.compute.internal * 172.16.101.9,192.168.71.192 projectcalico-default-allow\nip-172-16-102-63.us-west-2.compute.internal-auto-hep ip-172-16-102-63.us-west-2.compute.internal * 172.16.102.63,192.168.108.192 projectcalico-default-allow\n"})}),"\n",(0,s.jsx)(t.h3,{id:"apply-network-policy-to-automatic-host-endpoints",children:"Apply network policy to automatic host endpoints"}),"\n",(0,s.jsx)(t.p,{children:"To apply policy that targets all Kubernetes nodes, first add a label to the nodes.\nThe label will be synced to their automatic host endpoints."}),"\n",(0,s.jsxs)(t.p,{children:["For example, to add the label ",(0,s.jsx)(t.strong,{children:"kubernetes-host"})," to all nodes and their host endpoints:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"kubectl label nodes --all kubernetes-host=\n"})}),"\n",(0,s.jsx)(t.p,{children:"And an example policy snippet:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"apiVersion: projectcalico.org/v3\nkind: GlobalNetworkPolicy\nmetadata:\n name: all-nodes-policy\nspec:\n selector: has(kubernetes-host)\n #<rest of the policy>\n"})}),"\n",(0,s.jsxs)(t.p,{children:["To select a specific set of host endpoints (and their corresponding Kubernetes nodes), use a policy selector that selects a label unique to that set of host endpoints.\nFor example, if we want to add the label ",(0,s.jsx)(t.strong,{children:"environment=dev"}
1)," to nodes named node1 and node2:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"kubectl label node node1 environment=dev\nkubectl label node node2 environment=dev\n"})}),"\n",(0,s.jsxs)(t.p,{children:["With the labels in place and automatic host endpoints enabled, host endpoints for node1 and node2 will be updated with the ",(0,s.jsx)(t.strong,{children:"environment=dev"})," label.\nWe can write policy to select that set of nodes with a combination of selectors:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"apiVersion: projectcalico.org/v3\nkind: GlobalNetworkPolicy\nmetadata:\n name: some-nodes-policy\nspec:\n selector: has(kubernetes-host) && environment == 'dev'\n #<rest of the policy>\n"})}),"\n",(0,s.jsx)(t.h2,{id:"tutorial",children:"Tutorial"}),"\n",(0,s.jsx)(t.p,{children:"This tutorial will lock down Kubernetes node ingress to only allow SSH and required ports for Kubernetes to function.\nWe will apply two policies: one for the control plane nodes. and one for the worker nodes."}),"\n",(0,s.jsx)(t.admonition,{type:"note",children:(0,s.jsxs)(t.p,{children:['Note: This tutorial was tested on a cluster created with kubeadm v1.18.2 on AWS, using a "stacked etcd" ',(0,s.jsx)(t.a,{href:"https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/ha-topology/",children:"topology"}),". Stacked etcd topology means the etcd pods are running on the masters. kubeadm uses stacked etcd by default.\nIf your Kubernetes cluster is on a different platform, is running a variant of Kubernetes, or is running a topology with an external etcd cluster,\nplease review the required ports for control plane and worker nodes in your cluster and adjust the policies in this tutorial as needed."]})}),"\n",(0,s.jsx)(t.p,{children:"First, let's restrict ingress traffic to the control plane nodes. The ingress policy below contains three rules.\nThe first rule allows access to the API server port from anywhere. The second rule allows all traffic to localhost, which\nallows Kubernetes to access control plane processes. These control plane processes includes the etcd server client API, the scheduler, and the controller-manager.\nThis rule also allows localhost access to the kubelet API and calico/node health checks.\nAnd the final rule allows the etcd pods to peer with each other and allows the masters to access each others kubelet API."}),"\n",(0,s.jsx)(t.p,{children:"If you have not modified the failsafe ports, you should still have SSH access to the nodes after applying this policy.\nNow apply the ingress policy for the Kubernetes masters:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{children:"calicoctl apply -f - << EOF\napiVersion: projectcalico.org/v3\nkind: GlobalNetworkPolicy\nmetadata:\n name: ingress-k8s-masters\nspec:\n selector: has(node-role.kubernetes.io/control-plane)\n # This rule allows ingress to the Kubernetes API server.\n ingress:\n - action: Allow\n protocol: TCP\n destination:\n ports:\n # kube API server\n - 6443\n # This rule allows all traffic to localhost.\n - action: Allow\n destination:\n nets:\n - 127.0.0.0/8\n # This rule is required in multi-master clusters where etcd pods are colocated with the masters.\n # Allow the etcd pods on the masters to communicate with each other. 2380 is the etcd peer port.\n # This rule also allows the masters to access the kubelet API on other masters (including itself).\n - action: Allow\n protocol: TCP\n source:\n selector: has(node-role.kubernetes.io/control-plane)\n destination:\n ports:\n - 2380\n - 10250\nEOF\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Note that the above policy selects the standard ",(0,s.jsx)(t.strong,{children:"node-role.kubernetes.io/control-plane"})," label that kubeadm sets on control plane nodes."]}),"\n",(0,s.jsxs)(t.p,{children:["Next, we need to apply policy to restrict ingress to the Kubernetes workers.\nBefore adding the policy we will add a label to all of our worker nodes, which then gets added to its automatic host endpoint.\nFor this tutorial we will use ",(0,s.jsx)(t.strong,{children:"kubernetes-worker"}),". An example command to add the label to worker nodes:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"kubectl get node -l '!node-role.kubernetes.io/control-plane' -o custom-columns=NAME:.metadata.name | tail -n +2 | xargs -I{} kubectl label node {} kubernetes-worker=\n"})}),"\n",(0,s.jsx)(t.p,{children:"The workers' ingress policy consists of two rules. The first rule allows all traffic to localhost. As with the masters,\nthe worker nodes need to access their localhost kubelet API and calico/node healthcheck.\nThe second rule allows the masters to access the workers kubelet API. Now apply the policy:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{children:"calicoctl apply -f - << EOF\napiVersion: projectcalico.org/v3\nkind: GlobalNetworkPolicy\nmetadata:\n name: ingress-k8s-workers\nspec:\n selector: has(kubernetes-worker)\n # Allow all traffic to localhost.\n ingress:\n - action: Allow\n destination:\n net
1s:\n - 127.0.0.0/8\n # Allow only the masters access to the nodes kubelet API.\n - action: Allow\n protocol: TCP\n source:\n selector: has(node-role.kubernetes.io/control-plane)\n destination:\n ports:\n - 10250\nEOF\n"})}),"\n",(0,s.jsx)(t.h2,{id:"additional-resources",children:"Additional resources"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/calico/3.28/network-policy/hosts/protect-hosts-tutorial",children:"Protect hosts tutorial"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/calico/3.28/network-policy/services/kubernetes-node-ports",children:"Apply policy to Kubernetes node ports"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/calico/3.28/reference/resources/globalnetworkpolicy",children:"Global network policy"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"/calico/3.28/reference/resources/hostendpoint",children:"Host endpoints"})}),"\n"]})]})}function h(e={}){let{wrapper:t}={...(0,l.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},17869:function(e,t,o){o.d(t,{R:()=>i,x:()=>r});var n=o(82645);let s={},l=n.createContext(s);function i(e){let t=n.useContext(l);return n.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),n.createElement(l.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.