<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Andrew Suderman on Medium]]></title>
        <description><![CDATA[Stories by Andrew Suderman on Medium]]></description>
        <link>https://medium.com/@andrew_75600?source=rss-11b8b1bcae53------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*GLCZZFnKXqBYDyB_PHW3Jw.jpeg</url>
            <title>Stories by Andrew Suderman on Medium</title>
            <link>https://medium.com/@andrew_75600?source=rss-11b8b1bcae53------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 23:29:04 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@andrew_75600/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[7 Habits Of Highly Effective CI/CD Pipelines]]></title>
            <link>https://medium.com/uptime-99/7-habits-of-highly-effective-ci-cd-pipelines-45006e2cb550?source=rss-11b8b1bcae53------2</link>
            <guid isPermaLink="false">https://medium.com/p/45006e2cb550</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[cicd]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <dc:creator><![CDATA[Andrew Suderman]]></dc:creator>
            <pubDate>Tue, 05 Feb 2019 18:01:00 GMT</pubDate>
            <atom:updated>2019-07-19T20:04:24.341Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Gtc95Bh36YWymaBagB4iDw.jpeg" /><figcaption>Pipe Cover Photo by <a href="https://unsplash.com/photos/DByY8MbE9OE?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Azka Rayhansyah</a> on <a href="https://unsplash.com/search/photos/effective-pipeline?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>At <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=7%20Habits%20Of%20Highly%20Effective%20CI%2FCD%20Pipelines">Fairwinds</a> we take an opinionated approach on how CI/CD should be done when Docker and Kubernetes are involved. In the following sections, I will outline the guiding principles of our opinions, and then lay out a typical CI/CD workflow that we use. I’ll also share some code that will enable you to give it a shot if you want. None of these principles are brand new or earth-shattering, but the combination makes for a repeatable, sustainable, and safe CI/CD pipeline that many of our customers love.</p><h3>Guiding Principles</h3><h4>Containers Should Be Immutable</h4><p>Docker allows you to rewrite a tag when you push a container. A common example of this is the latest tag. This is a dangerous practice because it presents a possible scenario where you don’t know what code is running in your container. We instead take the approach that all tags are immutable, so we tie them to an immutable, unique value that can be found in our codebase — the commit ID. This directly connects a container to the code that it was built from and erases any doubt that we know exactly <em>what</em> is inside that container.</p><h4>Release The Container That Was Tested</h4><p>In line with the first principle, the immutable container that we have deployed to a staging/dev/QA environment and then tested (hopefully) should be the same exact container that gets deployed to production. This eliminates any concern that something might change when deployed to production. We handle this by triggering a release to production using a git tag and releasing the container with the commit ID of the tag.</p><h4>Keep Secrets And Config Out Of The Container</h4><p>Since a container should be considered an immutable artifact of our build process, configuration should never be “baked in.” Configuration should be stored in a <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/">configmap</a> in the Kubernetes cluster, and secrets should be stored, you guessed it, in Kubernetes <a href="https://kubernetes.io/docs/concepts/configuration/secret/">secrets</a>. This allows the deployment of the container to be configured per environment without making changes to the container itself.</p><h4>Deploy With Helm</h4><p>At <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=7%20Habits%20Of%20Highly%20Effective%20CI%2FCD%20Pipelines">Fairwinds</a>, we use <a href="https://helm.sh/">Helm</a> to template all of the yaml that gets deployed to Kubernetes. This allows the easy configuration of multiple environments and their config. In addition, it makes it easier to keep track of logical groupings or “releases.”</p><h4>Use A Git-Based Workflow</h4><p>All CI/CD pipelines should be triggered by Git operations. This falls in line with a normal developer workflow, and makes the pipeline more accessible to developers. In addition, it works well with the previous concept of immutability being tied to a commit ID.</p><h4>Build Inside Docker</h4><p>We strongly discourage the use of what a former co-worker referred to as “artisanal hand-crafted build machines” that contain a random assortment of dependencies and tools. If you build <em>inside</em> the container, you can control all dependencies and tools in your code and never have to worry about which “builder” is running your pipeline. Docker’s <a href="https://docs.docker.com/develop/develop-images/multistage-build/">multistage builds</a> make it easy to do this while also keeping your deployed runtime image as small as possible.</p><h4>Take Advantage Of Caching</h4><p>Docker images can be cached and re-used. We recommend the use of this feature as much as possible in order to keep build times to a minimum. The cache images should be pushed to a repository or the caching features of your CI/CD system should be used to maximize efficiency.</p><h3>Example Pipeline</h3><p>I’m going to lay out step-by-step a normal pipeline that we would set up for a customer. It takes into account all of the principles in the previous section, and will provide a path from code to production “In X easy steps!”</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/efbc0e0ea69a42540dbcf92c53fdaec0/href">https://medium.com/media/efbc0e0ea69a42540dbcf92c53fdaec0/href</a></iframe><p>The process goes like this:</p><ol><li>Make a feature branch</li><li>Push that branch and open a PR — this gets built and deployed to an ephemeral namespace that you can use to test the changes. Iterate until it’s ready to go</li><li>Merge the feature branch to master — this triggers a build and a deployment to a staging environment</li><li>Once the staging environment reaches a state that is ready for production, tag a release</li><li>The tag gets deployed to production using the same container that was built for staging, but using production configuration</li></ol><p>Looking at the process, we can see several “loops.” These are feedback loops that can be used to improve quality, test code, etc. The goal is to make these small and fast so that we can release code that is tested and manageable.</p><h3>Go Forth And Make Pipelines</h3><p>If you like the way we do CI/CD at <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=7%20Habits%20Of%20Highly%20Effective%20CI%2FCD%20Pipelines">Fairwinds</a>, you can have your very own pipelines just like ours! We use a set of bash scripts that do all of this for us. We just have to create some config files and we get a setup very similar to the one in this article. The repo is called <a href="https://github.com/reactiveops/rok8s-scripts">rok8s-scripts</a> (pronounced “rocket scripts”), and as always, PRs are accepted.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=45006e2cb550" width="1" height="1" alt=""><hr><p><a href="https://medium.com/uptime-99/7-habits-of-highly-effective-ci-cd-pipelines-45006e2cb550">7 Habits Of Highly Effective CI/CD Pipelines</a> was originally published in <a href="https://medium.com/uptime-99">uptime 99</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kubernetes 203 — Security Basics]]></title>
            <link>https://medium.com/uptime-99/kubernetes-203-security-basics-6af5aee0367d?source=rss-11b8b1bcae53------2</link>
            <guid isPermaLink="false">https://medium.com/p/6af5aee0367d</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Andrew Suderman]]></dc:creator>
            <pubDate>Mon, 28 Jan 2019 17:16:01 GMT</pubDate>
            <atom:updated>2019-07-19T20:02:09.938Z</atom:updated>
            <content:encoded><![CDATA[<h3>Kubernetes 203 — Security Basics</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*71onhUladNrxeQaIisVFUQ.jpeg" /><figcaption>Security Guard Cover Photo — by <a href="https://unsplash.com/photos/mth-DDkGqT0?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Ali Yahya</a> on <a href="https://unsplash.com/search/photos/security-guard?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>So you built a cluster. Maybe you have some apps deployed. You’re sold on this whole Kubernetes thing. Now what do you do?</p><p>There are a lot of things you can do next. You could install a bunch of tools to make your life easier (shameless plug for my <a href="https://medium.com/uptime-99/kubernetes-202-making-it-fully-operational-7416e4bb15ab">previous article</a>). You could just start deploying apps and running them in production. Or, you might be thinking to yourself “How on <em>earth</em> am I going to secure this massive complicated thing that I just put out there in the cloud!?!?” That’s a valid question, and I am going to make an attempt to answer it in a set of easy-to-follow practical steps.</p><p>Disclaimer: I’m not writing a thorough guide on securing your clusters, and I’m not making any claims that this information is perfect. It’s a starting point, a way to get the brain juices flowing and open the door to a full security plan.</p><h3>GKE</h3><p>I started my Kubernetes journey entirely in AWS thinking it was the Bees Knees™. Then I found out about GKE (Google Kubernetes Engine) and promptly changed my mind. Both platforms are awesome and have their drawbacks, but if you’re just starting out, GKE is a great place to do it.</p><p>The latest defaults in GKE are pretty good and they’re always being improved, but there are some settings you should choose when setting up your cluster that will give you the ability to do nice security bits later on.</p><h4>VPC-Native Cluster</h4><p>The first thing to do, is turn on a VPC-Native network configuration. This is relatively new in GKE, and will be the default soon. It puts your cluster inside a VPC, much like you would do in AWS. It’s only one checkbox away, and totally worth doing:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/954/1*WxC7EL2dTx8ZuLDOqc0RfA.png" /><figcaption>GKE VPC-Native Option</figcaption></figure><h4>Cluster Access</h4><p>After you’ve done that, there is a set of checkboxes related to cluster networking that I will go through. The first is here:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/968/1*9JYRl4p-7KejwMqHW3GN-A.png" /><figcaption>GKE Enable Master Authorized Networks</figcaption></figure><p>As you look at this, you might be thinking “Didn’t this guy just tell us a while back that IP Whitelisting isn’t a form of security, and we should just stop doing it?” (<a href="https://medium.com/uptime-99/my-ip-is-not-my-password-40d174c8f1c5">article</a>)r You would be mostly correct about that, and I tend to think that this step is largely unnecessary. However, as part of a larger security posture, this setting can be a great idea. This setting restricts access to your master nodes (and the Kubernetes API) to a specific set of IP addresses. This doesn’t mean that anyone on those IP addresses can magically just access your API because they still have to authenticate with Kubernetes to do anything. What it gives you is peace of mind that if a critical vulnerability in Kubernetes (see <a href="https://github.com/kubernetes/kubernetes/issues/71411">CVE-2018–1002105</a>) comes up, you have a little breathing room to fix it. This naturally has usability implications around public CI/CD tools and remote workers, but if all of your expected traffic to your cluster comes from inside a single network, then by all means turn on “Enable master authorized networks” and set it to that IP CIDR block.</p><h4>Network Policy</h4><p>The third checkbox we want to consider is <em>Enable network policy:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/380/1*4JlOyb_igu6YhISeF-FMwg.png" /><figcaption>GKE Enable Network Policy</figcaption></figure><p>This box sounds awesome, and it largely is. It enables a network policy implementation called “Calico” that allows you to create Kubernetes <a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/">network policy</a>. In turn, this provides the ability to heavily restrict what things can talk to other things in your cluster. It doesn’t give a lot of benefit out of the box, but it opens the door to a world of security. If you plan to do advanced network policy, then checking this box in the beginning will save you some hassle.</p><h4>Disable Legacy Authentication</h4><p>The last set of boxes control authentication with the Kubernetes API:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/942/1*F27x-7vHd5sVTXNcpINSTw.png" /><figcaption>GKE Settings Security Section — Auth</figcaption></figure><p>Pretty soon, the default options are going to be sufficient, but until then you need to uncheck <em>Enable Legacy Authentication</em>, <em>Issue Client Certificate</em>, and <em>Enable Legacy Authorization</em>. This disables basic authentication and forces all users to use GCP authentication in order to gain access to the cluster. In addition, Google enables RBAC by default so that we can control who has access to what in the cluster. I will cover this in more detail later.</p><h3>AWS (kops)</h3><p>By default, kops creates a cluster that is internal to the VPC with nodes in a private subnet, masters in a public one, an ELB for API access, and ssh only available internally. In general, this is a fantastic network configuration and doesn’t need many changes. Hats off to the kops developers on that one. However, there are a couple of settings that need to be added when creating your cluster to maximize your security.</p><h4>Cluster Access</h4><p>First, you can enable a whitelist of IPs that have access to the masters (see the GKE section for my thoughts on this). You can do this in the kops cluster yaml by adding this tidbit and replacing your IP CIDR blocks:</p><pre>spec:<br>  kubernetesApiAccess:<br>    - 203.0.113.0/24</pre><h4>Disable Anonymous Authentication</h4><p>Another easy change you can make is to turn off anonymous authentication for the kubelet. From <a href="https://github.com/kubernetes/kops/blob/master/docs/security.md#kubelet-api">Kops Security</a>:</p><pre>spec:<br>  kubelet:<br>    anonymousAuth: false</pre><h4>Network Policy</h4><p>If you want to enable network policy, you can do so by changing your network overlay. Calico or Canal are both good options that support network policy. I won’t cover it in detail here, but kops has a great <a href="https://github.com/kubernetes/kops/blob/master/docs/networking.md">bit of documentation</a> on this subject.</p><h4>Enable RBAC</h4><p>Next, you want to make sure that RBAC is enabled in your clusters. This is the default in new kops clusters, but it’s worth checking the cluster spec for this:</p><pre>spec:<br>  authorization:<br>    rbac: {}</pre><h4>Enable Audit Logging</h4><p>And the last setting you want is to turn on audit logging. GKE gives you this by default, but in kops we have to add it ourselves. At <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20203%20-%20Security%C2%A0Basics">Fairwinds</a>, we use the following configuration, which comes from the <a href="https://kubernetes.io/docs/tasks/debug-application-cluster/audit/">Kubernetes Docs</a>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0fb99ddbea6997bee8177d450dcb4178/href">https://medium.com/media/0fb99ddbea6997bee8177d450dcb4178/href</a></iframe><h3>Cluster Security</h3><p>Once you have the cluster built with all of these options, there’s even more you can do to enhance your security posture.</p><h4>Use RBAC</h4><p>It’s enabled now, so use it. The built-in policies can be useful, but you should think about your own as well. In addition, whenever you install a Helm chart, make sure that the very common rbac.enabled: true setting is on. This will create RBAC objects specific to that application. Go look at them and see what they do.</p><p>Use <a href="https://github.com/reactiveops/rbac-manager">RBAC Manager</a> to simplify the creation of RoleBindings and ClusterRoleBindings. This will enable you to create a simple CRD that binds Users/Groups/ServiceAccounts to Roles/ClusterRoles.</p><p>And finally, when you get deep in the weeds of RBAC and can’t for the life of you figure out why someone somehow does or doesn’t have access to something, use <a href="https://github.com/reactiveops/rbac-lookup">RBAC Lookup</a> to look it up.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TGd8tP-ohd27SRm7BClRfA.gif" /><figcaption>Brief Demo of rbac-lookup — <a href="https://asciinema.org/a/222327">https://asciinema.org/a/222327</a></figcaption></figure><h4>Use Namespaces Liberally</h4><p>To quote a co-worker, “Namespaces are cheap.” Use them to separate things like infrastructure tooling and applications. This allows you to restrict access easily using RBAC and to limit the scope of applications. I will also make your network policy creation easier when you decide to do it.</p><h3>Container Security</h3><p>Lastly, we need to to secure the workloads that we run in the cluster since these are what will be exposed to our (potentially hostile) users. There are a lot of things that are default or common when running containers in Kubernetes that provide less than ideal security. Here’s a non-exhaustive list of things you can do to get started.</p><h4>Don’t run multiple processes per container</h4><p>Docker general best practices suggest a single process per container simply for usability and size reasons, and this is actually a great practice to follow for security as well. It keeps your attack surface small and limits the number of potential vulnerabilities.</p><h4>Don’t run containers as privileged</h4><p>Running a container or pod as privileged gives it the ability to make modifications to the host. This is a large security issue that is super easy to mitigate by just not doing it.</p><h4>Don’t run containers as the root user</h4><p>By default, containers run as the root user inside the container. This is easy to avoid using the pod specification to set a high-numbered UID.</p><pre>spec:<br>  securityContext:<br>    runAsUser: 10324</pre><h4>Don’t use the default list of capabilities</h4><p>Docker runs containers with a significant set of Linux capabilities by default, many of which your app might not require. You can see them in the <a href="https://github.com/moby/moby/blob/master/oci/defaults.go#L14-L30">source code</a>. The following config will drop all Linux capabilities by default, allowing you to add only the specific capabilities your app actually needs:</p><pre>spec:<br>  containers:<br>  - name: foo<br>    securityContext:<br>      capabilities:<br>        drop:<br>          - ALL</pre><h4>Scan your containers for vulnerabilities</h4><p>Known vulnerabilities account for a large portion of breaches. Use a tool to scan your containers for them and then mitigate them. <a href="https://anchore.com/">Anchore</a>, <a href="https://github.com/coreos/clair">Clair</a>, and <a href="https://quay.io/">Quay</a> are among my favorite tools, but there are others out there.</p><h4>Look At KUBSEC.IO</h4><p>This tool will analyze your deployment yaml and tell you what you should change in order to improve the security of those pods. It even gives you a score that you can use to create a minimum standard. The score incorporates all of the best practices that I have outlined above, as well as several more.</p><p>Here’s an example of a deployment with a score of 9:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a117db13f9e4003a08ef11722928e033/href">https://medium.com/media/a117db13f9e4003a08ef11722928e033/href</a></iframe><h3>Don’t Stop Here</h3><p>There’s new stuff coming out all the time about Kubernetes and security. Go read it, and try it out. Just recently I read <a href="https://www.cncf.io/blog/2019/01/14/9-kubernetes-security-best-practices-everyone-must-follow/">an article on the CNCF blog</a> that had a good overview of security best practices and reminded me of some things that we should be doing better. Security is a complex web of multiple layers that can’t be solved with one tool, and it is never “done,” so please, don’t stop caring about it after you read this article.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6af5aee0367d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/uptime-99/kubernetes-203-security-basics-6af5aee0367d">Kubernetes 203 — Security Basics</a> was originally published in <a href="https://medium.com/uptime-99">uptime 99</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kubernetes 202 — Making It Fully Operational]]></title>
            <link>https://medium.com/uptime-99/kubernetes-202-making-it-fully-operational-7416e4bb15ab?source=rss-11b8b1bcae53------2</link>
            <guid isPermaLink="false">https://medium.com/p/7416e4bb15ab</guid>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Andrew Suderman]]></dc:creator>
            <pubDate>Wed, 14 Nov 2018 17:54:32 GMT</pubDate>
            <atom:updated>2019-07-19T19:59:45.438Z</atom:updated>
            <content:encoded><![CDATA[<h3>Kubernetes 202 — Making It Fully Operational</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J77I0ONm5csEVkeSmkCISw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/photos/O6DUoIl6NWA?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Jared Rice</a> on <a href="https://unsplash.com/search/photos/funny?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>A Kubernetes cluster is a powerful tool. It gives you the power to deploy your containerized workloads, automatically scale them, and schedule them across multiple machines. It can even open up a load balancer for your service to be exposed to the world (assuming you’re running in a supported cloud). Unfortunately, all of this functionality doesn’t come out of the box. You need DNS entries, path-based routing, TLS certificates, metrics, scaling, and role-based access control (RBAC). Over time at <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a> we have developed a set of tools that we run inside of every cluster which provide those various services. Our end goal is that any application can run in the cluster and have a human-readable address, a TLS cert, scale automatically, be able to utilize path-based routing, and only have the access that it needs. That’s no simple feat, with more than a few potential pitfalls along the way. This article should serve as a guide to taking a bare Kubernetes cluster and making it “fully operational.”</p><p><em>Disclaimer: This is intended as an intermediate guide. It assumes that you have a working Kubernetes cluster and understand most of the basic Kubernetes primitives.</em></p><h4>Initial Setup</h4><p>This guide is going to consist largely of installing tools and controllers into your cluster. At <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a> we use <a href="https://github.com/helm/helm">Helm</a>, a Kubernetes package manager, to install most (or all) of the various tools we use. In order to use Helm, you have to install the tiller into your cluster. This can be done using the Helm cli, with a dedicated service account for tiller, like so:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/de948cf0c8146348e9520cb5e2601c9a/href">https://medium.com/media/de948cf0c8146348e9520cb5e2601c9a/href</a></iframe><p>In addition to Helm, this guide is going to reference a Kubernetes deployment. If you are reading this, you already know what a deployment and a pod are. For ease of following the guide, I will be using the following deployment of a simple Nginx pod and building on it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c041d000591b57232e52c93dbb8fc9fc/href">https://medium.com/media/c041d000591b57232e52c93dbb8fc9fc/href</a></iframe><h4>Getting Traffic To Services</h4><p>Let’s talk about how we get traffic from outside the cluster to your services running inside the cluster. There are a few different ways that Kubernetes allows us to do this natively, and we should explore those first.</p><p><strong>NodePort Services</strong></p><p>A NodePort service is exactly what it sounds like: it opens a port on all the nodes that can be used to route traffic to the Kubernetes service. It is <a href="https://kubernetes.io/docs/concepts/services-networking/#nodeport">defined</a> in yaml like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ad269110235902ad2c22300945f4b1a2/href">https://medium.com/media/ad269110235902ad2c22300945f4b1a2/href</a></iframe><p>And it ends up looking like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e88f2c7aebbd76cc1e4eef2bf47d0d14/href">https://medium.com/media/e88f2c7aebbd76cc1e4eef2bf47d0d14/href</a></iframe><p>Notice we have an internal cluster IP, and that the port is defined as 80:32732. This indicates that when we try to reach any node on port 32732, we will be redirected to the service on port 80. It’s a useful construct, but it really only opens the door for an external load balancer to route the traffic. You don’t want to ask all of your customers to type 32732 at then end of our URLs.</p><p><strong>LoadBalancer Services</strong></p><p>In a supported cloud provider, a LoadBalancer service is awesome. It exposes a high port on all of the nodes in the cluster, and then it creates a cloud load balancer that uses that port to route traffic. The <a href="https://kubernetes.io/docs/concepts/services-networking/#loadbalancer">service definition</a> is remarkably simple:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ea0c8ff39822a9d1105f7e5f46d0e844/href">https://medium.com/media/ea0c8ff39822a9d1105f7e5f46d0e844/href</a></iframe><p>This creates a cloud load balancer in your cloud provider and attaches it to the port that it created. If we look at the service now, we see a couple of interesting things:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9992e4c4dad7e1e40930fe5453f0854f/href">https://medium.com/media/9992e4c4dad7e1e40930fe5453f0854f/href</a></iframe><p>First, we see that there is an external IP address marked as &lt;pending&gt; because our cloud provider is still creating the resource. Second, we see that the port listed for the service is 80:32732. This indicates that the service has exposed a NodePort that will be used as the listener port for the load balancer.</p><p>LoadBalancer services are powerful and highly configurable with cloud-provider specific annotations, but they have a few limitations. The biggest issue is that every service you expose creates a separate load balancer. In a world of tens or hundreds of microservices, this adds up a to a lot of cloud load balancers. LoadBalancer services also don’t provide opportunities for path-based routing. Again, in a world of microservices (or even regular services), this might be a non-starter.</p><p><strong>Ingress</strong></p><p>Given the limitations of NodePort and LoadBalancer services, we need something a little more powerful. The Kubernetes developers anticipated this need and created the Ingress object. Ingresses require that you run a controller in your cluster to handle them, and they are a little more difficult to get running right out of the gate, but the payoffs are huge.</p><p>As previously mentioned, in order to use Ingress we need a controller. <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-controllers">There are several controllers</a> out there, such as <a href="https://konghq.com/blog/kubernetes-ingress-controller-for-kong/">Kong</a> and <a href="https://www.haproxy.com/blog/haproxy_ingress_controller_for_kubernetes/">HAProxy</a>. At <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a> we have found <a href="https://github.com/kubernetes/ingress-nginx">ingress-nginx, an Nginx-based controller,</a> to be the easiest to use and one of the most complete solutions. There are many ways to install it, but we prefer to use <a href="https://helm.sh/">Helm</a>:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3f826813c9e0d88c36e2f39eff83dfea/href">https://medium.com/media/3f826813c9e0d88c36e2f39eff83dfea/href</a></iframe><p>This will create the Nginx controller and expose it to the world using the now-familiar LoadBalancer service:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0f63520d0b713d5299d304f3e00174c8/href">https://medium.com/media/0f63520d0b713d5299d304f3e00174c8/href</a></iframe><p>This service points to a set of controller pods that are running Nginx. Now we can create objects in Kubernetes called Ingresses that will configure Nginx to route traffic to our services inside the cluster.</p><p>Every service you deploy that needs to be exposed outside the cluster will now include an Ingress definition. Ingress definitions are also quite simple and look something like the following snippet:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/787a37dc4463df753c04a685b5be0cc1/href">https://medium.com/media/787a37dc4463df753c04a685b5be0cc1/href</a></iframe><p>Notice that it routes to the service we created. This tells Nginx to route traffic to that service when it comes into the cluster with the matching hostname. This is how we get path- and name-based routing. If we dig into the ingress controller pod and look at the config for Nginx, we will see a very familiar Nginx server block which corresponds to our new ingress.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e128b6c9f2eb564609ffa34450277210/href">https://medium.com/media/e128b6c9f2eb564609ffa34450277210/href</a></iframe><p>Like the LoadBalancer service, Ingresses can incorporate very detailed configuration using annotations. These annotations are Nginx specific, and can configure different options in the controller.</p><p>All of this means that we now have a way to run tens or hundreds of services behind a single Nginx proxy (or group of them), and these proxies are configured using easy to deploy Kubernetes objects. We can even use this to create TLS certificates and DNS, as we’ll see later. Right now we have a single cloud load balancer that handles TCP traffic to the controller, and we handle routing from inside the cluster. Here’s a little diagram to bring it all together:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iXPFksIqTrbCyhbznMp6Jg.png" /><figcaption>Ingress Traffic Diagram</figcaption></figure><h4>DNS Entry Creation</h4><p>Since we are using path- and name-based routing, we are going to need to create DNS entries. In the spirit of using controllers and other Kubernetes-native constructs, <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a> uses a project called <a href="https://github.com/kubernetes-incubator/external-dns">external-dns</a>. This controller will watch for annotations and certain types of objects and create DNS entries based on them. It is also deployed with Helm:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/315c793c2ab62bd591d9fb62f3dbcbf3/href">https://medium.com/media/315c793c2ab62bd591d9fb62f3dbcbf3/href</a></iframe><p><em>Note that credentials for your DNS provider will need to be specified as well, which depends on which DNS provider you are using. See </em><a href="https://medium.com/%20https://github.com/helm/charts/tree/master/stable/external-dns"><em>here</em></a><em> for more details.</em></p><p>Now when we create ingresses with DNS names, the external-dns controller will update our DNS provider with the IP address of the ingress controller.</p><h4>Encrypting Services With TLS</h4><p>Now that we have HTTP traffic to our services and easily accessible names, we want to secure them. HTTPS has become the de facto standard now that search engines optimize for it and browsers give ugly warnings if it’s not there. Traditionally this has been a pain point for operations teams. Back then, we had to generate the certs and do validation (sometimes from a manual portal), and then the certs still had to be deployed. Depending on the application we had to update application code or restart web servers. In the modern age, we have a few different options.</p><p><strong>Cloud Provider Cert Storage</strong></p><p>Amazon provides Amazon Certificate Manager (ACM). Combined with a LoadBalancer service and a special annotation, we can utilize an ACM cert to terminate TLS before it gets to the cluster. ACM automatically renews the certificate if you generate it using Route53 DNS. In a similar fashion, the ingress controller can incorporate a wildcard ACM certificate with its load balancer. This means that any Ingress we create that uses a domain in the wildcard gets TLS for free. This is a good option for a small number of services as long as you are comfortable with a wildcard. Some security policies don’t allow for it, and sometimes you want more than one subdomain. For another auto-validating option, we look further.</p><p><strong>Let’s Encrypt</strong></p><p>With the rise of cloud computing and privacy concerns, <a href="https://letsencrypt.org/about/">Let’s Encrypt</a> set out to create a Certificate Authority anyone can use free of charge and fully automated. They have a specific protocol that allows you to validate and generate a certificate automatically and programmatically. Many implementations of the protocol have been done, but we at <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a> focus on <a href="https://github.com/jetstack/cert-manager">cert-manager</a>. This tool utilizes a custom controller inside of Kubernetes that requests and maintains certificates from Let’s Encrypt. This is coupled with a shim that watches for new Ingress objects and automatically generates certificates for them.</p><p>What all of that means is that you can deploy the cert-manager and not worry about TLS certificates ever again. Of course, it’s a little more complicated than that, but once deployed it makes management of certificates seamless.</p><p>In order to deploy cert-manager, we use Helm again:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d55ab2701ed8a5fc613f922198d205d6/href">https://medium.com/media/d55ab2701ed8a5fc613f922198d205d6/href</a></iframe><p>Once the controller’s running, there are a few more pieces that need to be set up. There are two ways to do domain validation for certificates. We prefer to use DNS01 where possible at <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a>. In order to do this, your cluster nodes (or the cert manager) must have access to modify your DNS provider’s records. This is outside scope for this article, but it can be done with node roles in your cloud provider. The other option is to create a service account that you would then use in the following step.</p><p>Next you create an Issuer or ClusterIssuer which is responsible for configuring your Let’s Encrypt account and setting up the validation method that you’re going to use. For this guide I will use a ClusterIssuer and connect it to Let’s Encrypt. This is done by creating another Kubernetes resource:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bb38044bbdc103ae06bbc22921ccef5a/href">https://medium.com/media/bb38044bbdc103ae06bbc22921ccef5a/href</a></iframe><p>There are a few things going on here:</p><ol><li>It’s using Google Cloud DNS for validation</li><li>It’s using a service account for permissions to update DNS. The service account credentials are stored in a secret called dns-gcloud-config</li><li>The email address will be your Let’s Encrypt account name. Renewal email warnings will go here</li><li>This points at the Let’s Encrypt prod endpoint, so it will make valid certificates</li></ol><p>Once you apply this resource, the cert-manager controller will attempt to set up your Let’s Encrypt account. If you do a kubectl describe clusterissuer letsencrypt-prod, you’ll see a few lines like this at the bottom of the output indicating your account was registered:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/35532aa0b6aea52f7a786c388c03da16/href">https://medium.com/media/35532aa0b6aea52f7a786c388c03da16/href</a></iframe><p>Now that you have an issuer and we have the ingress controller, we can redeploy our Ingress object to utilize cert-manager:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3ce69ff62004ae4acfdca882948f9b57/href">https://medium.com/media/3ce69ff62004ae4acfdca882948f9b57/href</a></iframe><p>Notice the annotations that specify an ssl redirect and which ClusterIssuer to use in addition to the TLS block at the bottom of the ingress. There is also a secret name specified that cert-manager will use as the name for the certificate. We can verify that all of this is created like so:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cf6bdf7e1dbea05cefe291d38ce1f7b7/href">https://medium.com/media/cf6bdf7e1dbea05cefe291d38ce1f7b7/href</a></iframe><p>So now we have a functional ingress with automatic TLS encryption routing traffic to our cluster. This leaves one more piece of the puzzle in order to have a fully operational service in Kubernetes.</p><h4>Scaling Applications Using Metrics</h4><p>I’m going to lump scaling and metrics together because we can’t scale an application without some sort of metrics to scale on, and they can be configured quickly and easily together. Kubernetes has a built-in mechanism called a horizontal pod autoscaler that can be used to maintain the number of replicas in a deployment based on metrics. In order to do this, we have to expose the metrics to the Kubernetes API. Unless you’re on GKE, which gives you this automatically, the easiest way to get metrics is to deploy the <a href="https://medium.com/%20https://github.com/kubernetes-incubator/metrics-server">metrics-server</a> into the cluster. This is very simple using Helm:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a5f562c3f6e1cfbf8284b7558a3ce004/href">https://medium.com/media/a5f562c3f6e1cfbf8284b7558a3ce004/href</a></iframe><p>Once the controller starts and metrics are populated, we should be able to see resource utilization of pods and nodes like so:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c850b7afe6828b797da7a72daf95ce81/href">https://medium.com/media/c850b7afe6828b797da7a72daf95ce81/href</a></iframe><p>With metrics available, we can create a <a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/">horizontal pod autoscaler</a> (HPA) for our deployment. The HPA is defined as another object and looks like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fd34b449bc18bec1c9f47155489ab669/href">https://medium.com/media/fd34b449bc18bec1c9f47155489ab669/href</a></iframe><p>After a few minutes you can look at the HPA and see the current status:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5b791b3a592cfbafc78235d03fea77db/href">https://medium.com/media/5b791b3a592cfbafc78235d03fea77db/href</a></iframe><p>This setup will watch the CPU usage of the pods and try to keep them at or below 80% utilization based on the CPU limits set on the deployment (see the original deployment). If the utilization goes too high, the HPA will scale up, and if it goes down for a time, it will scale down. This behavior can be changed to use any metric via a custom metrics provider. Tuning this correctly will allow your deployment to handle many varying traffic and load problems.</p><h4>Scaling The Cluster</h4><p>Scaling pods horizontally is great and allows for dynamic traffic handling, but it doesn’t control how many nodes are in the cluster. As we add more and more pods, scaling them up, we are going to need more nodes to handle all of the pods. This will become obvious when you see a bunch of pods in a Pending status; when you do a kubectl describe pod &lt;pod-name&gt; you’ll see a message about not being able to schedule the pod. We handle this by utilizing cluster autoscaling. The cluster autoscaler project will scale up if new pods cannot be scheduled, and it will keep an eye on node utilization, scaling down if it sees an opportunity.</p><p>Installation looks very different depending on which cloud provider you are using, but I briefly will cover AWS and GKE setup.</p><p><strong>GKE</strong></p><p>This one is really easy. GKE runs the cluster autoscaler by default if you turn autoscaling on in your node pools. You can do this in the console, or using whatever code you used to set up your cluster:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/890/1*QZSJ2L9OtaXVyW24v8_4Pw.png" /><figcaption>GKE Node Pool Autoscaling Menu</figcaption></figure><p><strong>AWS</strong></p><p>This again depends on how you created your cluster, but at <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a> we use <a href="https://github.com/kubernetes/kops">kops</a>. No matter how you built your cluster (excluding EKS), you still need to install the <a href="https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler">cluster-autoscaler</a>. We use Helm to install the autoscaler using auto discovery of nodes.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9ec0103bb208caac4c1533efe0c0663c/href">https://medium.com/media/9ec0103bb208caac4c1533efe0c0663c/href</a></iframe><p>This requires modifying your kops cluster and instance group definitions. This is beyond the scope of this article, but it is well documented <a href="https://github.com/helm/charts/tree/master/stable/cluster-autoscaler#auto-discovery">here</a>.</p><h4>Permissions — RBAC</h4><p>Managing <a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/">RBAC</a> (role-based access control) in Kubernetes is difficult. The cluster you built most likely has it enabled by default, and you probably haven’t configured it at all. This tutorial has already made use of RBAC inside the Helm charts that we deployed.</p><p>Out of the box there’s a bunch of resources that you can define:</p><ul><li>serviceaccounts</li><li>clusterrolebindings</li><li>rolebindings</li><li>roles</li><li>clusterroles</li></ul><p>Keeping these straight is confusing, and modifying permissions usually requires multiple sets of definitions. <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a> utilizes a controller that we wrote to make it simpler called <a href="https://github.com/reactiveops/rbac-manager">rbac-manager</a>. We can install it with (you guessed it) Helm:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b1a1f250698039ff09b6140f6514508f/href">https://medium.com/media/b1a1f250698039ff09b6140f6514508f/href</a></iframe><p>We can now create an object called an rbacdefinition in order to manage our permissions and service accounts. Let’s go ahead and create one for our CI/CD system to use:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9143c00449f2c0a6608f122bc91c918c/href">https://medium.com/media/9143c00449f2c0a6608f122bc91c918c/href</a></iframe><p>Applying this will create a service account called ci and bind it to the cluster role cluster-admin. In the future we can generate a kubeconfig file for our ci system using that service account. Going forward we can add to this in order to finely control all permissions for users and service accounts in the cluster.</p><h4>That Was A Lot</h4><p>You just installed a TON of tools into your cluster and added a lot of functionality. What did we just add?</p><ul><li>Ingress Controller — For routing and TLS termination into the cluster</li><li>External DNS — Manages your DNS records for your ingresses</li><li>Cert Manager — Generates and maintains TLS certificates for the ingresses</li><li>Metrics Server — For enabling the use of Horizontal Pod Autoscalers</li><li>Cluster Autoscaler — For managing cluster size based on pods</li><li>RBAC-Manager — For managing your cluster permissions</li></ul><p>All of these required one or more Helm charts to install, and may require different values depending on customizations that you want to make. It can be frustrating to run these commands and maintain these values files, especially if you manage multiple clusters. <a href="https://www.fairwinds.com/?utm_campaign=uptime%2099&amp;utm_source=medium&amp;utm_medium=uptime%2099&amp;utm_content=Kubernetes%20202%20-%20Making%20It%20Fully%20Operational">Fairwinds</a> utilizes a homegrown tool called <a href="https://github.com/reactiveops/autohelm">Autohelm</a> to manage all of these charts. It allows you to maintain a single file that defines all of the charts you want to use. There are examples of all the different charts being deployed in the <a href="https://github.com/reactiveops/autohelm/blob/master/examples.md">examples.md</a>.</p><h4>Something Something Great Responsibility</h4><p>Now you have the awesome power of a “fully operational” Kubernetes cluster. Go forth and deploy services that are auto-scaling, highly available, and TLS encrypted. Please hit me up <a href="https://twitter.com/SudermanJr">@sudermanjr</a> with comments or requests for future topics.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7416e4bb15ab" width="1" height="1" alt=""><hr><p><a href="https://medium.com/uptime-99/kubernetes-202-making-it-fully-operational-7416e4bb15ab">Kubernetes 202 — Making It Fully Operational</a> was originally published in <a href="https://medium.com/uptime-99">uptime 99</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[My IP Is Not My Password]]></title>
            <link>https://medium.com/uptime-99/my-ip-is-not-my-password-40d174c8f1c5?source=rss-11b8b1bcae53------2</link>
            <guid isPermaLink="false">https://medium.com/p/40d174c8f1c5</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[networking]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[security]]></category>
            <dc:creator><![CDATA[Andrew Suderman]]></dc:creator>
            <pubDate>Mon, 08 Oct 2018 22:33:57 GMT</pubDate>
            <atom:updated>2018-10-08T22:33:57.142Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YiuxJFsUpJ7x-qQa7bQ5MQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/photos/bBavss4ZQcA?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Jon Moore</a> on <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>In the last several years, I’ve seen an alarming number of requests to implement a system where we allow access based on the user’s IP address. In my experience this creates a false sense of security and causes a significant amount of pain, specifically in cloud environments. But before I go on, a brief history of the internet and security to give context.</p><h4>A Brief History of the Internet¹</h4><ul><li><strong>1983 </strong>— Vint and Bob create TCP/IP V4 and it is implemented in ARPANET</li><li><strong>1985 </strong>— People start hoarding IPv4 CIDR blocks</li><li><strong>1999 </strong>— Cloud computing becomes a thing</li><li><strong>2002 </strong>— Static IPs are limited and start changing frequently</li></ul><h4>A Brief History of Security¹</h4><ul><li><strong>1988 — </strong>People realize that static IPv4 addresses are a thing</li><li><strong>1990 — </strong>Companies use whitelists to allow traffic according to these IPv4 addresses</li><li><strong>1991 — </strong>Companies think this is a good idea</li></ul><p>I may have missed some stuff here. You get the point. IP whitelisting became the first security implementation that every network admin deployed for years. More frequently (and more terrifyingly), they just stopped right there.</p><h4>What’s wrong with that?</h4><p>Let’s talk about the implications of using IPs as your only security measure. First, IP spoofing is a thing. Of course this will not allow bi-directional attacks, but it can be used in DOS attacks. Secondly, BGP hijacking can be used to attack these types of defenses.</p><p>These are fairly sophisticated attacks that would require a serious attacker, however they make a good case for why this should not be your only security mechanism.</p><p>An even bigger issue with IP filtering is that the modern use of cloud computing makes this type of security measure entirely untenable. Most cloud instances don’t use static IP addresses by default. Cloud providers only have a limited amount of IP space, and they aren’t going to just hand it out to everyone. The much more common use case is that every time a resource is created, it gets a random new IP, or even better, it gets an internal address and is hidden behind some form of gateway. With good reason, cloud providers are urging people to use models that consume fewer IP addresses.²</p><p>This means that we need to stop relying on static IP addresses as a security mechanism. &lt;/rant&gt;</p><h4>Isn’t it better than nothing?</h4><p>In the world of tech, we frequently talk about security by saying, “Anything is better than nothing.” You can’t really argue with this statement because of how vague and obvious it is. I want to encourage everyone that works in technology to stop saying this and instead start asking “How do we implement security that is <em>good enough</em>?” This question encourages us to reconsider our entire strategy and decide if it’s enough to protect the value of our business. A strategy might include IP blacklisting on a large scale to avoid traffic from known dangerous actors, or it might include any number of other measures that by themselves are inadequate but put together provide good security. Let’s get rid of the defeatist attitude of “better than nothing” and focus on security that’s “good enough”.</p><p><em>¹Please note that the dates in the article are almost entirely fictional and should not be taken as fact</em></p><p><em>²AWS documentation specifically states that IPv4 addresses are scarce. </em><a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-limit"><em>https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-limit</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=40d174c8f1c5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/uptime-99/my-ip-is-not-my-password-40d174c8f1c5">My IP Is Not My Password</a> was originally published in <a href="https://medium.com/uptime-99">uptime 99</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>