{"id":4751,"date":"2026-04-01T21:41:40","date_gmt":"2026-04-01T16:11:40","guid":{"rendered":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/"},"modified":"2026-04-01T21:41:40","modified_gmt":"2026-04-01T16:11:40","slug":"cybersecurity-best-practices-guide","status":"publish","type":"post","link":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/","title":{"rendered":"Cybersecurity Best Practices &#8211; Guide"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_80 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-69f09feeaf5b9\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-69f09feeaf5b9\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#Your_%E2%80%9CCybersecurity_Best_Practices%E2%80%9D_Are_Probably_Just_Security_Theater\" >Your &#8220;Cybersecurity Best Practices&#8221; Are Probably Just Security Theater<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#The_Compliance_Lie_and_the_Reality_of_IAM\" >The Compliance Lie and the Reality of IAM<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#The_Container_Security_Myth_Alpine_vs_The_World\" >The Container Security Myth: Alpine vs. The World<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#Secrets_Management_Environment_Variables_are_Not_a_Vault\" >Secrets Management: Environment Variables are Not a Vault<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#The_Network_is_Hostile_Even_the_%E2%80%9CInternal%E2%80%9D_One\" >The Network is Hostile (Even the &#8220;Internal&#8221; One)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#Dependency_Hell_npm_audit_is_a_Liar\" >Dependency Hell: npm audit is a Liar<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#Logging_If_You_Didnt_Log_It_It_Didnt_Happen\" >Logging: If You Didn&#8217;t Log It, It Didn&#8217;t Happen<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#The_%E2%80%9CGotcha%E2%80%9D_The_Hidden_Danger_of_Infrastructure_as_Code\" >The &#8220;Gotcha&#8221;: The Hidden Danger of Infrastructure as Code<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#The_Wrap-up\" >The Wrap-up<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#Related_Articles\" >Related Articles<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Your_%E2%80%9CCybersecurity_Best_Practices%E2%80%9D_Are_Probably_Just_Security_Theater\"><\/span>Your &#8220;Cybersecurity Best Practices&#8221; Are Probably Just Security Theater<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>I once took down an entire payment processing cluster because I thought I was being clever with <code>iptables<\/code>. We were trying to implement &#8220;cybersecurity best&#8221; practices\u2014specifically, egress filtering. I pushed a script to 400 nodes that blocked all outbound traffic except for a whitelist of IPs. I forgot that our internal service discovery relied on a gossip protocol using a dynamic port range. Within ninety seconds, the nodes stopped talking to each other. The health checks failed. The load balancer, seeing 100% unhealthy targets, did exactly what it was programmed to do: it stopped routing traffic. We went dark. Total silence on the wire for forty-five minutes while I scrambled to find a serial console because I\u2019d locked myself out of SSH too.<\/p>\n<p>That\u2019s the reality of security. It\u2019s not a checklist of &#8220;best practices&#8221; you find on a LinkedIn infographic. It\u2019s a series of expensive, painful trade-offs that usually break your observability tools before they stop a single hacker. Most of the advice you read online is written by people who have never had to rotate a root CA certificate on a live production database at 3:00 AM. They talk about &#8220;defense in depth&#8221; like it\u2019s a magical shield, but they don&#8217;t tell you that every layer of defense adds a layer of operational complexity that will eventually cause a self-inflicted Denial of Service. If you want to actually secure a system, you have to stop thinking about &#8220;features&#8221; and start thinking about &#8220;failure modes.&#8221;<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Compliance_Lie_and_the_Reality_of_IAM\"><\/span>The Compliance Lie and the Reality of IAM<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Most companies think they are secure because they passed a SOC2 audit. SOC2 is a joke. It\u2019s a test of your ability to generate screenshots, not your ability to prevent a lateral movement attack. You can have a &#8220;perfect&#8221; security posture on paper and still have a developer who hardcoded an AWS Secret Key into a <code>docker-compose.yml<\/code> file that got pushed to a public GitHub repo. The industry obsesses over &#8220;cybersecurity best&#8221; practices like password rotation, which actually just encourages people to write their passwords on Post-it notes or append a &#8220;!&#8221; to the end of their old one. It&#8217;s useless.<\/p>\n<p>Identity and Access Management (IAM) is where most people fail. They use the <code>AdministratorAccess<\/code> policy because &#8220;we&#8217;re a small team and we need to move fast.&#8221; That is technical debt with a high interest rate. If you give a Lambda function <code>s3:*<\/code> permissions just to read one config file, you are one RCE (Remote Code Execution) away from losing your entire data lake. IAM is hard because it&#8217;s verbose and the feedback loop is slow. You try to run a Terraform plan, it fails with a 403, you add a permission, it fails again. It\u2019s exhausting.<\/p>\n<blockquote>\n<p>Pro-tip: Use <code>aws-vault<\/code> or <code>gcloud auth application-default login<\/code>. Never, under any circumstances, let a raw <code>.aws\/credentials<\/code> file live on your local disk in plaintext. If your laptop gets snatched at a coffee shop, your entire infrastructure is gone in the time it takes to run a <code>grep<\/code> command.<\/p>\n<\/blockquote>\n<p>When you&#8217;re defining IAM policies, you need to use Condition blocks. A simple <code>Allow<\/code> on <code>s3:PutObject<\/code> isn&#8217;t enough. You need to restrict it by VPC ID or IP range. Look at this mess of a policy that most people think is &#8220;fine&#8221;:<\/p>\n<pre><code>{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": \"s3:*\",\n            \"Resource\": \"arn:aws:s3:::prod-customer-data\/*\"\n        }\n    ]\n}\n<\/code><\/pre>\n<p>That is a disaster. If an attacker gains access to the compute instance running this, they can delete the entire bucket. They can change the bucket policy to make it public. They can even set up a lifecycle rule to transition everything to Glacier Deep Archive, effectively holding your data hostage. A real &#8220;best practice&#8221; looks like this:<\/p>\n<ul>\n<li>Explicitly list actions: <code>s3:GetObject<\/code>, <code>s3:PutObject<\/code>. No wildcards.<\/li>\n<li>Use <code>StringEquals<\/code> conditions to ensure the request comes from your specific VPC endpoint.<\/li>\n<li>Implement MFA-delete on the bucket itself so no single compromised credential can wipe the data.<\/li>\n<li>Use <code>ResourceTag<\/code> constraints so the policy only applies to buckets tagged with <code>Project: Payments<\/code>.<\/li>\n<li>Enable S3 Block Public Access at the account level. No exceptions.<\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"The_Container_Security_Myth_Alpine_vs_The_World\"><\/span>The Container Security Myth: Alpine vs. The World<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Everyone loves Alpine Linux. It\u2019s small. It\u2019s &#8220;secure&#8221; because it has a tiny attack surface. That\u2019s the hype. The reality is that Alpine uses <code>musl<\/code> instead of <code>glibc<\/code>. I\u2019ve spent more hours debugging weird DNS resolution issues and memory allocation bugs in Alpine than I have actually writing code. When your Node.js app suddenly starts throwing <code>EAI_AGAIN<\/code> errors under load, it\u2019s usually because of how Alpine handles <code>\/etc\/resolv.conf<\/code>. Security shouldn&#8217;t come at the cost of basic stability.<\/p>\n<p>I\u2019ve moved almost everything to <code>debian-slim<\/code> or Google\u2019s <code>distroless<\/code> images. Yes, the image is 50MB larger. Who cares? Disk space is cheap; my time is expensive. <code>distroless<\/code> is the gold standard because it doesn\u2019t even have a shell. If an attacker gets into your container, they can\u2019t run <code>ls<\/code>, <code>cd<\/code>, or <code>curl<\/code>. They are trapped in a void. But there\u2019s a catch: you can\u2019t <code>kubectl exec<\/code> into it to debug. You have to use ephemeral debug containers, which requires a modern Kubernetes version (1.23+).<\/p>\n<p>Here is a Dockerfile that actually follows &#8220;cybersecurity best&#8221; principles without making your life a living hell:<\/p>\n<pre><code># Use a specific hash, not just a tag. Tags are mutable.\nFROM node:20.11.0-bookworm-slim@sha256:d31630ed53b46f60251bc3f32a499a2f269199c405020284419f972b68f07893\n\n# Create a system group and user. Never run as root.\nRUN groupadd -r appuser && useradd -r -g appuser appuser\n\n# Set the working directory\nWORKDIR \/usr\/src\/app\n\n# Copy only what is needed\nCOPY --chown=appuser:appuser package*.json .\/\nRUN npm ci --only=production\n\nCOPY --chown=appuser:appuser . .\n\n# Drop all capabilities and then add only what is strictly necessary\n# This is usually handled in the K8s SecurityContext, but good to keep in mind\nUSER appuser\n\nEXPOSE 3000\nCMD [\"node\", \"server.js\"]\n<\/code><\/pre>\n<p>Notice I used <code>npm ci<\/code>. It\u2019s faster and more reliable than <code>npm install<\/code> because it uses the <code>package-lock.json<\/code> strictly. If there\u2019s a mismatch, it fails. This prevents &#8220;dependency drift&#8221; where a sub-dependency gets updated to a malicious version during your build process. We saw this with the <code>event-stream<\/code> incident. It\u2019s real.<\/p>\n<p>Also, stop using <code>latest<\/code> tags. I don&#8217;t care if it&#8217;s for your base image or your own app. <code>latest<\/code> is a ticking time bomb. One day you&#8217;ll trigger a redeploy and pull a version that has a breaking change or a new vulnerability, and you won&#8217;t even know which version you&#8217;re running because the logs just say <code>image: my-app:latest<\/code>. Use the Git commit SHA as the tag. It provides an immutable link between your code and your artifact.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Secrets_Management_Environment_Variables_are_Not_a_Vault\"><\/span>Secrets Management: Environment Variables are Not a Vault<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If I see one more &#8220;best practices&#8221; guide suggesting you put API keys in environment variables, I\u2019m going to lose it. Environment variables are incredibly leaky. They show up in <code>ps aux<\/code>, they get dumped in crash logs, and they are inherited by every child process. If your app spawns a shell script for some reason, that script now has your Stripe secret key. If you use a monitoring tool like Datadog or New Relic, and it captures an OOM-kill event, it might dump the environment variables into its dashboard. Now your secrets are in a third-party SaaS.<\/p>\n<p>Use a real secrets provider. HashiCorp Vault is the industry standard, but it\u2019s a beast to manage. If you\u2019re on AWS, Secrets Manager is fine, but it\u2019s slow. The latency on a <code>GetSecretValue<\/code> call can be 100ms+. If you\u2019re doing that on every request, you\u2019re killing your performance. You need to cache secrets in memory, but then you have to handle rotation. When the secret rotates in the background, your app is still using the old one until it restarts or the cache expires.<\/p>\n<blockquote>\n<p>Note to self: If using AWS Secrets Manager with Lambda, use the extension. It handles the caching and rotation logic for you so you don&#8217;t have to write a bunch of boilerplate <code>if (cache_expired)<\/code> logic.<\/p>\n<\/blockquote>\n<p>For local development, use <code>sops<\/code> (Secrets Operations). It allows you to encrypt your <code>secrets.yaml<\/code> file using AWS KMS or GCP KMS and commit the encrypted file to Git. It looks like this:<\/p>\n<pre><code>api_key: ENC[AES256_GCM,data:asdf...=,tag:...]\ndb_password: ENC[AES256_GCM,data:1234...=,tag:...]\nsops:\n    kms:\n        - arn: aws:kms:us-east-1:123456789012:key\/mrk-1234\n<\/code><\/pre>\n<p>This way, your developers can pull the repo, run <code>sops -d secrets.enc.yaml<\/code>, and get the keys they need (assuming they have the correct IAM permissions to use that KMS key). It\u2019s a clean, auditable workflow. No more sharing passwords over Slack or storing them in <code>.env<\/code> files that eventually get committed by accident because someone messed up their <code>.gitignore<\/code>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Network_is_Hostile_Even_the_%E2%80%9CInternal%E2%80%9D_One\"><\/span>The Network is Hostile (Even the &#8220;Internal&#8221; One)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The &#8220;Cybersecurity Best&#8221; practice of the 2010s was the &#8220;Castle and Moat&#8221; strategy. You have a strong firewall at the edge, and everything inside is trusted. This is how the Google Aurora hack happened. This is how every major ransomware attack spreads. Once an attacker gets a foothold on a single low-priority dev server, they can scan the entire internal network because there are no internal firewalls.<\/p>\n<p>You need to assume the network is already compromised. This is &#8220;Zero Trust,&#8221; but without the marketing fluff. In practice, this means:<\/p>\n<ul>\n<li><strong>mTLS (Mutual TLS):<\/strong> Every service must verify the identity of every other service. It&#8217;s not enough for the client to trust the server; the server must trust the client. Tools like Linkerd or Istio make this easier, but they add a massive amount of YAML-hell and sidecar overhead. If you&#8217;re small, use Tailscale or Wireguard to create a flat, encrypted overlay network.<\/li>\n<li><strong>No more 0.0.0.0:<\/strong> Bind your services to <code>localhost<\/code> or a specific internal interface. If your Redis instance doesn&#8217;t need to be accessed from outside the node, bind it to <code>127.0.0.1<\/code>. It sounds simple, but you&#8217;d be surprised how many &#8220;internal&#8221; databases are listening on all interfaces.<\/li>\n<li><strong>Metadata Service Protection:<\/strong> If you&#8217;re on AWS, block access to <code>169.254.169.254<\/code> for everything except the IAM role provider. SSRF (Server-Side Request Forgery) is a top-tier threat. An attacker can use your own app to query the metadata service and steal the instance&#8217;s temporary IAM credentials.<\/li>\n<li><strong>Egress Control:<\/strong> This is what I messed up in my war story, but it&#8217;s still necessary. Your payment service should only be able to talk to <code>api.stripe.com<\/code>. It has no business talking to a random IP in eastern Europe. Use a proxy or a specialized egress controller to enforce this.<\/li>\n<\/ul>\n<p>Let&#8217;s talk about the &#8220;Confused Deputy&#8221; problem. This happens when a service with high privileges is tricked by a less-privileged user into performing an action. For example, an internal &#8220;PDF Generator&#8221; service might take a URL and render it. If that service has an IAM role that can read from S3, an attacker could give it a URL like <code>file:\/\/\/etc\/passwd<\/code> or <code>http:\/\/169.254.169.254\/latest\/meta-data\/iam\/security-credentials\/<\/code>. The PDF generator happily renders your secrets into a PDF and hands it to the attacker. This isn&#8217;t a &#8220;bug&#8221; in the traditional sense; it&#8217;s a failure of architectural boundaries.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Dependency_Hell_npm_audit_is_a_Liar\"><\/span>Dependency Hell: npm audit is a Liar<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If you run <code>npm audit<\/code>, you will see 4,000 vulnerabilities. 3,995 of them are &#8220;ReDoS&#8221; (Regular Expression Denial of Service) in some dev-dependency used by a build tool you only run once a month. This creates &#8220;alert fatigue.&#8221; You start ignoring the audit because it&#8217;s mostly noise. Then, a real vulnerability like <code>log4shell<\/code> comes along, and you miss it because it&#8217;s buried under 500 warnings about a markdown parser.<\/p>\n<p>You need a better signal-to-noise ratio. Use <code>trivy<\/code> or <code>snyk<\/code>, but configure them to only alert on &#8220;High&#8221; or &#8220;Critical&#8221; vulnerabilities that are actually in your production dependency tree. Even then, you have to be skeptical. Just because a library has a vulnerability doesn&#8217;t mean your app is vulnerable. If the vulnerability is in a function you don&#8217;t call, you&#8217;re fine. But try explaining that to a compliance auditor.<\/p>\n<p>The real &#8220;cybersecurity best&#8221; move here is to minimize dependencies. Do you really need <code>left-pad<\/code>? Do you really need <code>lodash<\/code> for a single <code>cloneDeep<\/code> call? Every dependency is a liability. Every dependency is a piece of code you didn&#8217;t write, don&#8217;t understand, but are now responsible for securing. I\u2019ve started favoring the standard library whenever possible. Modern Node.js and Go have incredible standard libraries that cover 90% of what we used to need external packages for.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Logging_If_You_Didnt_Log_It_It_Didnt_Happen\"><\/span>Logging: If You Didn&#8217;t Log It, It Didn&#8217;t Happen<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>When you get breached\u2014and you will\u2014the first thing you\u2019ll do is look at the logs. If your logs just say <code>GET \/api\/v1\/user 200<\/code>, you are screwed. You need context. But you have to be careful not to log PII (Personally Identifiable Information). I\u2019ve seen developers log the entire request body, including passwords and credit card numbers, &#8220;for debugging purposes.&#8221; That is a massive security violation in itself.<\/p>\n<p>A good log entry should include:<\/p>\n<ul>\n<li>The <code>Request-ID<\/code> (to trace the request across microservices).<\/li>\n<li>The <code>User-ID<\/code> or <code>Subject<\/code> from the JWT.<\/li>\n<li>The <code>X-Forwarded-For<\/code> header (to see the real client IP).<\/li>\n<li>The specific resource ID being accessed.<\/li>\n<li>The latency of the request.<\/li>\n<li>The version of the code that handled the request.<\/li>\n<\/ul>\n<p>And for the love of all that is holy, use structured logging (JSON). Grepping through plain text logs is for the 90s. If you want to find all requests from a specific IP that resulted in a 403, you should be able to run a simple SQL-like query in ELK or Datadog, not a complex <code>awk<\/code> script that breaks if the log format changes by one space.<\/p>\n<pre><code>{\n  \"timestamp\": \"2024-05-20T14:32:01.123Z\",\n  \"level\": \"WARN\",\n  \"message\": \"Unauthorized access attempt\",\n  \"request_id\": \"req-99283475\",\n  \"client_ip\": \"203.0.113.42\",\n  \"user_id\": \"user_8823\",\n  \"path\": \"\/api\/v1\/admin\/settings\",\n  \"method\": \"POST\",\n  \"status\": 403\n}\n<\/code><\/pre>\n<p>This format is machine-readable. You can set up an automated alert that triggers if the number of 403s from a single <code>client_ip<\/code> exceeds 100 in a minute. That\u2019s how you catch a credential stuffing attack in real-time, not three weeks later when you&#8217;re doing a post-mortem.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_%E2%80%9CGotcha%E2%80%9D_The_Hidden_Danger_of_Infrastructure_as_Code\"><\/span>The &#8220;Gotcha&#8221;: The Hidden Danger of Infrastructure as Code<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We all love Terraform. It\u2019s great for &#8220;cybersecurity best&#8221; practices because it makes your infrastructure auditable. But Terraform state files are a nightmare. The <code>terraform.tfstate<\/code> file contains <em>everything<\/em> in plaintext. If you create a database using Terraform, the master password is in that state file. If you create an IAM access key, the secret key is in that state file.<\/p>\n<p>If you store your state file in an S3 bucket that isn&#8217;t properly secured, you\u2019ve just handed the keys to the kingdom to anyone who can read that bucket. You must:<\/p>\n<ol>\n<li>Enable server-side encryption on the S3 bucket.<\/li>\n<li>Restrict access to the bucket to only the CI\/CD runner&#8217;s IAM role.<\/li>\n<li>Enable versioning on the bucket so you can recover from an accidental deletion.<\/li>\n<li>Use a DynamoDB table for state locking to prevent race conditions that can corrupt your infrastructure.<\/li>\n<\/ol>\n<p>I once saw a team that had their Terraform state in a public S3 bucket because they &#8220;wanted to make it easy for the whole team to see.&#8221; They were lucky they were a tiny startup that no one had heard of, or they would have been wiped out in hours. This is the kind of &#8220;expert&#8221; knowledge that doesn&#8217;t show up in the &#8220;Getting Started&#8221; guides.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"The_Wrap-up\"><\/span>The Wrap-up<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Security isn&#8217;t a product you buy or a single &#8220;best practice&#8221; you implement; it&#8217;s a constant, grinding process of reducing your attack surface while trying not to kill your team&#8217;s velocity. Stop chasing the latest &#8220;AI-powered&#8221; security tool and start doing the boring stuff: fix your IAM policies, use distroless images, encrypt your secrets at rest, and actually look at your logs. The most secure system is the one that is simple enough to understand, because you can&#8217;t protect what you don&#8217;t understand. Don&#8217;t build a glass house and then try to buy the most expensive curtains; just build a smaller, stronger house.<\/p>\n<p>Stop reading blogs and go audit your <code>0.0.0.0<\/code> bindings.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Related_Articles\"><\/span>Related Articles<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Explore more insights and best practices:<\/p>\n<ul>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/openstreetmap-api-in-android-open-source-approach-for-free-mapping\/\">Openstreetmap Api In Android Open Source Approach For Free Mapping<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/machine-learning-best-practices-7-tips-for-success\/\">Machine Learning Best Practices 7 Tips For Success<\/a><\/li>\n<li><a href=\"https:\/\/itsupportwale.com\/blog\/10-essential-cybersecurity-tips-to-protect-your-data-2\/\">10 Essential Cybersecurity Tips To Protect Your Data 2<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Your &#8220;Cybersecurity Best Practices&#8221; Are Probably Just Security Theater I once took down an entire payment processing cluster because I thought I was being clever with iptables. We were trying to implement &#8220;cybersecurity best&#8221; practices\u2014specifically, egress filtering. I pushed a script to 400 nodes that blocked all outbound traffic except for a whitelist of IPs. &#8230; <a title=\"Cybersecurity Best Practices &#8211; Guide\" class=\"read-more\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/\" aria-label=\"Read more  on Cybersecurity Best Practices &#8211; Guide\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4751","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Cybersecurity Best Practices - Guide - ITSupportWale<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Cybersecurity Best Practices - Guide - ITSupportWale\" \/>\n<meta property=\"og:description\" content=\"Your &#8220;Cybersecurity Best Practices&#8221; Are Probably Just Security Theater I once took down an entire payment processing cluster because I thought I was being clever with iptables. We were trying to implement &#8220;cybersecurity best&#8221; practices\u2014specifically, egress filtering. I pushed a script to 400 nodes that blocked all outbound traffic except for a whitelist of IPs. ... Read more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/\" \/>\n<meta property=\"og:site_name\" content=\"ITSupportWale\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\" \/>\n<meta property=\"article:published_time\" content=\"2026-04-01T16:11:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"512\" \/>\n\t<meta property=\"og:image:height\" content=\"512\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Techie\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Techie\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/\"},\"author\":{\"name\":\"Techie\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\"},\"headline\":\"Cybersecurity Best Practices &#8211; Guide\",\"datePublished\":\"2026-04-01T16:11:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/\"},\"wordCount\":2508,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/\",\"name\":\"Cybersecurity Best Practices - Guide - ITSupportWale\",\"isPartOf\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\"},\"datePublished\":\"2026-04-01T16:11:40+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/itsupportwale.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Cybersecurity Best Practices &#8211; Guide\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#website\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"name\":\"ITSupportWale\",\"description\":\"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides\",\"publisher\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#organization\",\"name\":\"itsupportwale\",\"url\":\"https:\/\/itsupportwale.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"contentUrl\":\"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png\",\"width\":1119,\"height\":144,\"caption\":\"itsupportwale\"},\"image\":{\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Itsupportwale-298547177495978\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d\",\"name\":\"Techie\",\"sameAs\":[\"https:\/\/itsupportwale.com\",\"iswblogadmin\"],\"url\":\"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Cybersecurity Best Practices - Guide - ITSupportWale","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/","og_locale":"en_US","og_type":"article","og_title":"Cybersecurity Best Practices - Guide - ITSupportWale","og_description":"Your &#8220;Cybersecurity Best Practices&#8221; Are Probably Just Security Theater I once took down an entire payment processing cluster because I thought I was being clever with iptables. We were trying to implement &#8220;cybersecurity best&#8221; practices\u2014specifically, egress filtering. I pushed a script to 400 nodes that blocked all outbound traffic except for a whitelist of IPs. ... Read more","og_url":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/","og_site_name":"ITSupportWale","article_publisher":"https:\/\/www.facebook.com\/Itsupportwale-298547177495978","article_published_time":"2026-04-01T16:11:40+00:00","og_image":[{"width":512,"height":512,"url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2021\/05\/android-chrome-512x512-1.png","type":"image\/png"}],"author":"Techie","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Techie","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#article","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/"},"author":{"name":"Techie","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d"},"headline":"Cybersecurity Best Practices &#8211; Guide","datePublished":"2026-04-01T16:11:40+00:00","mainEntityOfPage":{"@id":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/"},"wordCount":2508,"commentCount":0,"publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/","url":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/","name":"Cybersecurity Best Practices - Guide - ITSupportWale","isPartOf":{"@id":"https:\/\/itsupportwale.com\/blog\/#website"},"datePublished":"2026-04-01T16:11:40+00:00","breadcrumb":{"@id":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/itsupportwale.com\/blog\/cybersecurity-best-practices-guide\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/itsupportwale.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Cybersecurity Best Practices &#8211; Guide"}]},{"@type":"WebSite","@id":"https:\/\/itsupportwale.com\/blog\/#website","url":"https:\/\/itsupportwale.com\/blog\/","name":"ITSupportWale","description":"Tips, Tricks, Fixed-Errors, Tutorials &amp; Guides","publisher":{"@id":"https:\/\/itsupportwale.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/itsupportwale.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/itsupportwale.com\/blog\/#organization","name":"itsupportwale","url":"https:\/\/itsupportwale.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","contentUrl":"https:\/\/itsupportwale.com\/blog\/wp-content\/uploads\/2023\/09\/cropped-Logo-trans-without-slogan.png","width":1119,"height":144,"caption":"itsupportwale"},"image":{"@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Itsupportwale-298547177495978"]},{"@type":"Person","@id":"https:\/\/itsupportwale.com\/blog\/#\/schema\/person\/8c5a2b3d36396e0a8fd91ec8242fd46d","name":"Techie","sameAs":["https:\/\/itsupportwale.com","iswblogadmin"],"url":"https:\/\/itsupportwale.com\/blog\/author\/iswblogadmin\/"}]}},"_links":{"self":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4751","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/comments?post=4751"}],"version-history":[{"count":0,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/posts\/4751\/revisions"}],"wp:attachment":[{"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/media?parent=4751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/categories?post=4751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itsupportwale.com\/blog\/wp-json\/wp\/v2\/tags?post=4751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}