<?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"><channel><title><![CDATA[DevOps Blogs]]></title><description><![CDATA[A blog about DevOps field by Gilang Wibowo]]></description><link>https://devops.gilangwibowo.com</link><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 23:04:29 GMT</lastBuildDate><atom:link href="https://devops.gilangwibowo.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Implementing Policy Controller in Google Cloud Kubernetes Engine (GKE)]]></title><description><![CDATA[Introduction
In today's cloud-native environment, managing policies at scale is crucial for maintaining security, compliance, and operational consistency. Google Cloud Kubernetes Engine (GKE) offers robust tools for policy enforcement, with Policy Co...]]></description><link>https://devops.gilangwibowo.com/implementing-policy-controller-in-google-cloud-kubernetes-engine-gke</link><guid isPermaLink="true">https://devops.gilangwibowo.com/implementing-policy-controller-in-google-cloud-kubernetes-engine-gke</guid><category><![CDATA[#policy-controller]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[google cloud]]></category><category><![CDATA[google kubernetes engine]]></category><dc:creator><![CDATA[Gilang Adhi Wibowo]]></dc:creator><pubDate>Tue, 16 Jul 2024 09:50:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721121835515/b1dbd249-6336-4e68-9fb7-8a2eb3bfcbe6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Introduction</p>
<p>In today's cloud-native environment, managing policies at scale is crucial for maintaining security, compliance, and operational consistency. Google Cloud Kubernetes Engine (GKE) offers robust tools for policy enforcement, with Policy Controller being a key component. This article will guide you step-by-step through implementing a Policy Controller in GKE. <strong>Note: Policy Controller is available if you use Google Kubernetes Engine (GKE) Enterprise edition.</strong></p>
<p><strong>Table of Contents</strong></p>
<ol>
<li><p>Introduction to Policy Controller</p>
</li>
<li><p>Prerequisites</p>
</li>
<li><p>Enabling Policy Controller</p>
</li>
<li><p>Install Policy Controller</p>
</li>
<li><p>Sync Cluster With Fleet Setting to have Policy Controller</p>
</li>
<li><p>Verify Template Library of policy controller is Installed</p>
</li>
<li><p>Testing Constraint Policies</p>
</li>
<li><p>Auditing Using Constraint</p>
</li>
<li><p>Conclusion</p>
</li>
</ol>
<hr />
<h3 id="heading-1-introduction-to-policy-controller">1. Introduction to Policy Controller</h3>
<p>Policy Controller is a Kubernetes admission controller that uses Open Policy Agent (OPA) to enforce policies. It ensures that all changes to your Kubernetes resources comply with specified policies before they are applied. This helps in maintaining security, compliance, and best practices across your clusters.</p>
<hr />
<h3 id="heading-2-prerequisites">2. Prerequisites</h3>
<p>Before we begin, ensure you have the following:</p>
<ul>
<li><p>A Google Cloud Platform (GCP) account</p>
</li>
<li><p>Google Cloud SDK installed on your local machine</p>
</li>
<li><p>kubectl installed on your local machine</p>
</li>
<li><p>Basic understanding of Kubernetes and GKE</p>
</li>
</ul>
<hr />
<h3 id="heading-3-enabling-policy-controller">3. Enabling Policy Controller</h3>
<ul>
<li><p>From Console -&gt; Search Bar -&gt; Type "Enabled API &amp; Service"</p>
</li>
<li><p>Find and enable <strong>Anthos Policy Controller API</strong></p>
</li>
</ul>
<ol>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721031248023/f87c9f85-1d8b-45b6-84c0-94adfa138346.png" alt class="image--center mx-auto" /></li>
</ol>
<hr />
<h3 id="heading-4-install-policy-controller">4. Install Policy Controller</h3>
<p>Policy Controller can be installed in <strong>fleet settings level</strong>, make sure you have GKE Enterprise, to install policy controller:</p>
<ul>
<li><p><strong>Enable Policy Controller in fleet setting</strong></p>
<ol>
<li><p>From Console -&gt; Kubernetes Engine -&gt; Feature Manager -&gt; configure</p>
<ul>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721117926328/3f83df18-7396-49a7-b12d-c74e46b016a2.png" alt class="image--center mx-auto" /></li>
</ul>
</li>
<li><p>Under Kubernetes Engine Tab -&gt; Policy -&gt; Settings -&gt; Configure Fleet Setting</p>
<ul>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721117771018/c533d590-e1c6-4611-a8fa-bc1254759c2b.png" alt class="image--center mx-auto" /></li>
</ul>
</li>
<li><p>Feature Manager -&gt; Customize Fleet Setting</p>
<ul>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721118349022/1eaa6942-ae21-4aa7-be78-40e61836a2e5.png" alt class="image--center mx-auto" /></li>
</ul>
</li>
<li><p>Make sure that Template Library is installed in fleet.</p>
<ul>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721118539326/977b6882-f89d-4fc8-9c81-2c257f294e1f.png" alt class="image--center mx-auto" /></li>
</ul>
</li>
</ol>
</li>
</ul>
<hr />
<h3 id="heading-5-sync-cluster-with-fleet-setting-to-have-policy-controller">5. Sync Cluster With Fleet Setting to have Policy Controller</h3>
<p>After we have enabled policy controller to <strong>Fleet Settings Level</strong>, we can attach cluster that we want to have policy controller:</p>
<ul>
<li><p><strong>Sync Cluster to have Policy Controller</strong></p>
<ol>
<li><p>From Console -&gt; Kubernetes Engine -&gt; Under Posture Management -&gt; Policy -&gt; Sync With Fleet Settings</p>
<ul>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721119819299/33bb8a45-a38d-4c5b-904b-d39a91c5b222.png" alt class="image--center mx-auto" /></li>
</ul>
</li>
<li><p>Under Kubernetes Engine Tab -&gt; Feature Manager -&gt; Check Desired Cluster -&gt; Sync To Fleet Setting -&gt; Make sure in sync with fleet is "yes"</p>
<ul>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721120236118/7b4119fa-5b1c-4739-ae1b-8a148511f975.png" alt class="image--center mx-auto" /></li>
</ul>
</li>
</ol>
</li>
</ul>
<hr />
<h3 id="heading-6-verify-template-library-of-policy-controller-is-installed">6. Verify Template Library of policy controller is Installed</h3>
<p>Policy Controller is a Kubernetes admission controller that uses Open Policy Agent (OPA) to enforce policies. Google Offers various of constrain template available for us. To Make sure Steps 4.4 is installed, use the command below:</p>
<pre><code class="lang-bash">$ kubectl get constrainttemplates
</code></pre>
<hr />
<h3 id="heading-7-testing-constraint-policies">7. Testing Constraint Policies</h3>
<p>For this time we will use "<strong>K8sRequiredLabels</strong>" that applied in namespaces for testing policies. The following constraint, called k8s-ns-must-have-label, invokes a constraint template called K8sRequiredLabels, which is included in the constraint <a target="_blank" href="https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/latest/reference/constraint-template-library">template library provided by Google</a>. The constraint defines parameters that the constraint template uses to evaluate whether namespaces have the "istio-injection" label set to some value.</p>
<pre><code class="lang-yaml"><span class="hljs-comment">#k8s-ns-must-have-label.yaml</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">constraints.gatekeeper.sh/v1beta1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">K8sRequiredLabels</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">k8s-ns-must-have-label</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">enforcementAction:</span> <span class="hljs-string">deny</span>
  <span class="hljs-attr">match:</span>
    <span class="hljs-attr">kinds:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">apiGroups:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">""</span>
      <span class="hljs-attr">kinds:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">Namespace</span>
  <span class="hljs-attr">parameters:</span>
    <span class="hljs-attr">labels:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">key:</span> <span class="hljs-string">istio-injection</span>
    <span class="hljs-attr">message:</span> <span class="hljs-string">you</span> <span class="hljs-string">must</span> <span class="hljs-string">provide</span> <span class="hljs-string">labels</span> <span class="hljs-string">istio-injection</span>
</code></pre>
<pre><code class="lang-bash">$ kubectl apply -f k8s-ns-must-have-label.yaml
</code></pre>
<p>To verify:</p>
<pre><code class="lang-bash">$ kubectl get constraint
<span class="hljs-comment">#output</span>
NAME                                                                 ENFORCEMENT-ACTION   TOTAL-VIOLATIONS
k8srequiredlabels.constraints.gatekeeper.sh/k8s-ns-must-have-label   deny                 8
</code></pre>
<p>To Testing, we can create namespace and the error will show up such as following command.</p>
<pre><code class="lang-bash">$ kubectl create ns stg-test
Error from server (Forbidden): admission webhook <span class="hljs-string">"validation.gatekeeper.sh"</span> denied the request: [k8s-ns-must-have-label] you must provide labels istio-injection
</code></pre>
<hr />
<h3 id="heading-8-auditing-using-constraint">8. Auditing Using Constraint</h3>
<p>Policy Controller constraint objects enable you to enforce policies for your Kubernetes clusters. To help test your policies, you can add an enforcement action to your constraints. You can then view violations in constraint objects and logs.</p>
<p><strong>Types of enforcement actions</strong></p>
<p>There are three enforcement actions: <strong>deny, dryrun, and warn</strong>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>deny</strong></td><td>dryrun</td><td>warn</td></tr>
</thead>
<tbody>
<tr>
<td>default enforcement action. It's automatically enabled, even if you don't add an enforcement action in your constraint. Use deny to prevent a given cluster operation from occurring when there's a violation.</td><td>lets you monitor violations of your rules without actively blocking transactions. You can use it to test if your constraints are working as intended, prior to enabling active enforcement using the deny action. Testing constraints this way can prevent disruptions caused by an incorrectly configured constraint.</td><td>similar to dryrun, but also provides an immediate message about the violations that occur at admission time.</td></tr>
</tbody>
</table>
</div><hr />
<h3 id="heading-9-conclusion">9. Conclusion</h3>
<p>Using a policy controller in Google Kubernetes Engine (GKE) offers several significant benefits, enhancing the security, compliance, and management of your Kubernetes clusters. Here's a summary of the key advantages:</p>
<ul>
<li><p>Enhanced Security and Compliance</p>
</li>
<li><p>Centralized Policy Management</p>
</li>
<li><p>Reduces the manual effort required to audit and enforce policies</p>
</li>
</ul>
<p>In conclusion, using a policy controller in GKE provides robust security, ensures compliance, and improves operational efficiency by automating policy enforcement and centralizing policy management. This results in a more secure, compliant, and well-governed Kubernetes environment.</p>
]]></content:encoded></item><item><title><![CDATA[Implementing ArgoCD Image Updater using Artifact Registry Google Cloud Platform]]></title><description><![CDATA[Overview
The Argo CD Image Updater can check for new versions of the container images that are deployed with your Kubernetes workloads and automatically update them to their latest allowed version using Argo CD.
Usage is simple: You annotate your Arg...]]></description><link>https://devops.gilangwibowo.com/implementing-argocd-image-updater-using-artifact-registry-google-cloud-platform</link><guid isPermaLink="true">https://devops.gilangwibowo.com/implementing-argocd-image-updater-using-artifact-registry-google-cloud-platform</guid><category><![CDATA[ArgoCD]]></category><category><![CDATA[gitops]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Git]]></category><category><![CDATA[GCP]]></category><category><![CDATA[GCP DevOps]]></category><dc:creator><![CDATA[Gilang Adhi Wibowo]]></dc:creator><pubDate>Fri, 21 Jun 2024 11:59:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718939609044/e517abf9-e2af-4e51-a728-7233c5817502.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-overview">Overview</h3>
<p>The Argo CD Image Updater can check for new versions of the container images that are deployed with your Kubernetes workloads and automatically update them to their latest allowed version using Argo CD.</p>
<p>Usage is simple: You annotate your Argo CD <code>Application</code> resources with a list of images to be considered for update, along with a version constraint to restrict the maximum allowed new version for each image. Argo CD Image Updater then regularly polls the configured applications from Argo CD and queries the corresponding container registry for possible new versions. If a new version of the image is found in the registry, and the version constraint is met, Argo CD Image Updater instructs Argo CD to update the application with the new image.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719071688160/c3a093c8-533b-4b87-ab1b-1a2248d07886.jpeg" alt class="image--center mx-auto" /></p>
<p>There are 4 <a target="_blank" href="https://argocd-image-updater.readthedocs.io/en/stable/#features">update strategies</a> available for Argo CD image updater:</p>
<ul>
<li><p><code>semver</code>: update to highest allowed version according to given image constraint,</p>
</li>
<li><p><code>latest</code>: update to the most recently created image tag,</p>
</li>
<li><p><code>name</code>: update to the last tag in an alphabetically sorted list</p>
</li>
<li><p><code>digest</code>: update to the most recent pushed version of a mutable tag</p>
</li>
</ul>
<p>And for this tutorial, we will use <a target="_blank" href="https://argocd-image-updater.readthedocs.io/en/stable/basics/update-strategies/#strategy-digest">digest update strategies</a>.</p>
<h3 id="heading-installation">Installation</h3>
<p>You can install the Image Updater alongside Argo CD, typically as a separate pod within the same namespace as Argo CD:</p>
<pre><code class="lang-plaintext">kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml
</code></pre>
<h3 id="heading-usage">Usage</h3>
<ol>
<li><p><strong>Authenticate to Artifact Registry</strong></p>
<p> To fully utilize the Argo CD Image Updater, it’s crucial to configure it to <a target="_blank" href="https://argocd-image-updater.readthedocs.io/en/stable/basics/authentication/#authentication-to-container-registries">connect with your image registry properly</a>, especially if you are using private registries or private repositories on public registries. Make sure you have service account key file with json format with appropriate permissions. Please read <a target="_blank" href="https://cloud.google.com/iam/docs/service-accounts-create">Create Service Account</a> for more information.</p>
<pre><code class="lang-plaintext"> cat sa-gcr-prd.json | docker login -u _json_key --password-stdin https://asia-southeast2-docker.pkg.dev
</code></pre>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718939747401/fd06884f-2a71-4205-a308-14579f40b25c.png" alt class="image--center mx-auto" /></p>
<p> The second step is to create secret from docker config file, so the ArgoCD Image Updater can use that for scanning dan watch every time there are new images pushed. Mostly docker saved the credential to authenticate with Registry in <strong>/home/user/.docker/config.json</strong> so you can take that file for generating secret.</p>
<pre><code class="lang-yaml">  <span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
 <span class="hljs-attr">kind:</span> <span class="hljs-string">Secret</span>
 <span class="hljs-attr">metadata:</span>
   <span class="hljs-attr">name:</span> <span class="hljs-string">gcr-prd</span>
   <span class="hljs-attr">namespace:</span> <span class="hljs-string">argocd</span>
 <span class="hljs-attr">data:</span>
   <span class="hljs-string">.dockerconfigjson:</span> <span class="hljs-string">&lt;base64</span> <span class="hljs-string">encoded</span> <span class="hljs-string">dockerconfigjson&gt;</span>
 <span class="hljs-attr">type:</span> <span class="hljs-string">kubernetes.io/dockerconfigjson</span>
</code></pre>
</li>
<li><p><strong>Configuring ArgoCD Image Updater</strong></p>
<p> After setting up the credentials, include them in the <a target="_blank" href="https://argocd-image-updater.readthedocs.io/en/stable/configuration/registries/#configuration-format">ArgoCD Image Updater’s configurationto authenticate with the image regis</a>try.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
 <span class="hljs-attr">kind:</span> <span class="hljs-string">ConfigMap</span>
 <span class="hljs-attr">metadata:</span>
   <span class="hljs-attr">labels:</span>
     <span class="hljs-attr">app.kubernetes.io/name:</span> <span class="hljs-string">argocd-image-updater-config</span>
     <span class="hljs-attr">app.kubernetes.io/part-of:</span> <span class="hljs-string">argocd-image-updater</span>
   <span class="hljs-attr">name:</span> <span class="hljs-string">argocd-image-updater-config</span>
 <span class="hljs-attr">data:</span>
   <span class="hljs-attr">git.commit-message-template:</span> <span class="hljs-string">|
     Auto-commit by Argocd Image Updater [{{ .AppName }}]
</span>
     {{ <span class="hljs-string">range</span> <span class="hljs-string">.AppChanges</span> <span class="hljs-string">-</span>}}
     <span class="hljs-string">updates</span> <span class="hljs-string">image</span> {{ <span class="hljs-string">.Image</span> }} <span class="hljs-string">tag</span> <span class="hljs-string">'<span class="hljs-template-variable">{{ .OldTag }}</span>'</span> <span class="hljs-string">to</span> <span class="hljs-string">'<span class="hljs-template-variable">{{ .NewTag }}</span>'</span>
     {{ <span class="hljs-string">end</span> <span class="hljs-string">-</span>}}
   <span class="hljs-attr">log.level:</span> <span class="hljs-string">debug</span>
   <span class="hljs-attr">registries.conf:</span> <span class="hljs-string">|
     registries:
     - name: asia-southeast2-docker.pkg.dev
       api_url: https://asia-southeast2-docker.pkg.dev
       ping: no
       credentials: pullsecret:argocd/gcr-prd #namespaceName/secretName
       defaultns: library
       prefix: asia-southeast2-docker.pkg.dev</span>
</code></pre>
<p> As i mentioned above, we annotate Argo CD <code>Application</code> resources with a list of images to be considered for update, and here is the example.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">apiVersion:</span> <span class="hljs-string">argoproj.io/v1alpha1</span>
 <span class="hljs-attr">kind:</span> <span class="hljs-string">Application</span>
 <span class="hljs-attr">metadata:</span>
   <span class="hljs-attr">name:</span> <span class="hljs-string">your-argocd-app-name</span>
   <span class="hljs-attr">namespace:</span> <span class="hljs-string">argocd</span>
   <span class="hljs-attr">labels:</span>
     <span class="hljs-attr">key:</span> <span class="hljs-string">value</span>
   <span class="hljs-attr">finalizers:</span>
     <span class="hljs-bullet">-</span> <span class="hljs-string">resources-finalizer.argocd.argoproj.io</span>
   <span class="hljs-attr">annotations:</span>
     <span class="hljs-attr">notifications.argoproj.io/subscribe.on-deployed.slack:</span> <span class="hljs-string">report-argocd</span>
     <span class="hljs-attr">notifications.argoproj.io/subscribe.on-sync-failed.slack:</span> <span class="hljs-string">report-argocd</span>
     <span class="hljs-attr">argocd-image-updater.argoproj.io/image-list:</span> <span class="hljs-string">frontend=asia-southeast2-docker.pkg.dev/PROJECT-ID/REPOSITORY/IMAGE:tag,backend=asia-southeast2-docker.pkg.dev/PROJECT-ID/REPOSITORY/IMAGE:tag</span>
     <span class="hljs-attr">argocd-image-updater.argoproj.io/frontend.update-strategy:</span> <span class="hljs-string">digest</span>
     <span class="hljs-attr">argocd-image-updater.argoproj.io/backend.update-strategy:</span> <span class="hljs-string">digest</span>
     <span class="hljs-attr">argocd-image-updater.argoproj.io/write-back-method:</span> <span class="hljs-string">git</span>
 <span class="hljs-attr">spec:</span>
   <span class="hljs-attr">project:</span> <span class="hljs-string">your-argocd-project-name</span>
   <span class="hljs-attr">source:</span>
     <span class="hljs-attr">repoURL:</span> <span class="hljs-string">https://gitlab.com/your-gitops-repository/repository.git</span>
     <span class="hljs-attr">targetRevision:</span> <span class="hljs-string">your-branch-name</span>
     <span class="hljs-attr">path:</span> <span class="hljs-string">target-folder-git</span>
   <span class="hljs-attr">destination:</span>
     <span class="hljs-attr">server:</span> <span class="hljs-string">https://your-cluster-external-endpoint</span>
     <span class="hljs-attr">namespace:</span> <span class="hljs-string">your-target-deployed-to</span>
   <span class="hljs-attr">syncPolicy:</span>
     <span class="hljs-attr">automated:</span>
       <span class="hljs-attr">selfHeal:</span> <span class="hljs-literal">true</span>
       <span class="hljs-attr">prune:</span> <span class="hljs-literal">true</span>
</code></pre>
</li>
<li><p>Once everything is applied, Argo CD Image updater will be able to do this kind of commit to your repository, and Argo CD will do the rest:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718971002252/93b48cab-d6f9-4563-8d62-4f899d47321b.png" alt class="image--center mx-auto" /></p>
<p> If you are interested in testing it, I hope this post showed you how <strong>easy it is to configure</strong> Argo CD Image Updater for your infrastructure. 😄</p>
</li>
</ol>
]]></content:encoded></item></channel></rss>