<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Articles by Toni Schmidbauer on TechBlog about OpenShift/Ansible/Satellite and much more</title><link>https://blog.stderr.at/authors/toni-schmidbauer/</link><description>TechBlog about OpenShift/Ansible/Satellite and much more</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>Toni Schmidbauer &amp; Thomas Jungbauer</copyright><atom:link href="https://blog.stderr.at/authors/toni-schmidbauer/index.xml" rel="self" type="application/rss+xml"/><item><title>Onboarding to Ansible Automation Platform with Configuration as Code</title><link>https://blog.stderr.at/ansible/2026/03/onboarding-to-ansible-automation-platform-with-configuration-as-code/</link><pubDate>Wed, 04 Mar 2026 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/ansible/2026/03/onboarding-to-ansible-automation-platform-with-configuration-as-code/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;We had the honor of presenting at the 2nd Ansible Anwendertreffen in
Austria. The topic was the onboarding of application teams to the
Ansible Automation Platform.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We created an extensive demo that:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Onboards a new tenant into an AAP organization.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Each tenant gets a configuration as code repository, &lt;a href="https://github.com/tosmi-ansible/template-org-config" target="_blank" rel="noopener"&gt;cloned from a template&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A push event to the config-as-code repository triggers an update of AAP objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provides an &lt;a href="https://github.com/tosmi-ansible/template-example-project" target="_blank" rel="noopener"&gt;example repository&lt;/a&gt; for each tenant to get started.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The example repository provides a &lt;a href="https://github.com/tosmi-ansible/template-org-config/blob/main/playbooks/devenv.yaml" target="_blank" rel="noopener"&gt;webhook&lt;/a&gt; that creates an OpenShift Virtualization VM for testing code changes when a feature branch is created.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Contains a &lt;a href="https://github.com/tosmi-ansible/template-org-config/blob/main/playbooks/cac-diff.yaml" target="_blank" rel="noopener"&gt;playbook&lt;/a&gt; to display objects that are not currently managed by the tenant’s configuration-as-code repository.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The source code for the demo is available on &lt;a href="https://github.com/tosmi-ansible/aap-onboarding" target="_blank" rel="noopener"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The &lt;a href="https://github.com/tosmi-ansible/aap-onboarding/blob/main/README.md"&gt;README&lt;/a&gt; contains more details about the implementation, and the slide deck is also &lt;a href="https://github.com/tosmi-ansible/aap-onboarding/blob/main/docs/Ansible%20Anwender%20Treffen%20202602%20-%20Slides.pdf" target="_blank" rel="noopener"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;</description></item><item><title>OKD Single node installation in a disconnected environment</title><link>https://blog.stderr.at/openshift-platform/infrastructure/2026-02-09-okd-sno-disconnected/</link><pubDate>Mon, 09 Feb 2026 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/infrastructure/2026-02-09-okd-sno-disconnected/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;Because of reasons we had to set up a disconnected single node OKD &amp;#34;cluster&amp;#34;. This is our brain dump as the
OKD documentation sometimes refers to OpenShift image locations, we had to read multiple sections to get it working and we
also consulted the OpenShift documentation at &lt;a href="https://docs.redhat.com" class="bare"&gt;https://docs.redhat.com&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Updated on 2026-03-03: Fixed install-config.yaml and create manifest command
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;First we need to download the &lt;em&gt;oc&lt;/em&gt; command in the version we would like to install. OKD provides it on its release page:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://github.com/okd-project/okd/releases/download/4.21.0-okd-scos.3/openshift-client-linux-amd64-rhel9-4.21.0-okd-scos.3.tar.gz" class="bare"&gt;https://github.com/okd-project/okd/releases/download/4.21.0-okd-scos.3/openshift-client-linux-amd64-rhel9-4.21.0-okd-scos.3.tar.gz&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To get an overview of releases available for OKD see &lt;a href="https://amd64.origin.releases.ci.openshift.org/" class="bare"&gt;https://amd64.origin.releases.ci.openshift.org/&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Another option is to extract the &lt;em&gt;oc&lt;/em&gt; command from the release image, if you have a version of &lt;em&gt;oc&lt;/em&gt; already installed:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-shell hljs" data-lang="shell"&gt;oc adm release extract --tools quay.io/okd/scos-release:4.21.0-okd-scos.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This will also extract the &lt;em&gt;openshift-install&lt;/em&gt; tar.gz which we need later to generate the installation manifests and ignition configs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Next we need the &lt;em&gt;oc-mirror&lt;/em&gt; plugin, which is used to mirror the release content to our local registry. We were only able to find the plugin on &lt;em&gt;console.redhat.com&lt;/em&gt;. Another option might be to compile the plugin from source code (&lt;a href="https://github.com/openshift/oc-mirror/" class="bare"&gt;https://github.com/openshift/oc-mirror/&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We copied the &lt;em&gt;oc&lt;/em&gt; command and the &lt;em&gt;oc-mirror&lt;/em&gt; plugin to /usr/local/bin/ and made them executable. After that we ran &lt;em&gt;oc mirror --v2 --help&lt;/em&gt; to test the installation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The upstream &lt;a href="https://github.com/openshift/oc-mirror/blob/main/docs/okd-mirror.md"&gt;oc-mirror&lt;/a&gt; plugin documentation was also helpful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;As our private registry required authentication, we created a .dockerconfigjson file with the registry credentials:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-json hljs" data-lang="json"&gt;{
&amp;#34;auths&amp;#34;: {
&amp;#34;internal.registry&amp;#34;: {
&amp;#34;auth&amp;#34;: &amp;#34;&amp;lt;credentials base64 encoded&amp;gt;&amp;#34;,
&amp;#34;email&amp;#34;: &amp;#34;you@example.com&amp;#34;
}
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;You can encode the credentials with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-shell hljs" data-lang="shell"&gt;echo -n &amp;#34;username:password&amp;#34; | base64 -w0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;For mirroring all required OKD images to our private registry we created an &lt;em&gt;ImageSetConfiguration&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v2alpha1
mirror:
platform:
channels:
- name: 4-scos-stable
minVersion: 4.21.0-okd-scos.3
maxVersion: 4.21.0-okd-scos.3
graph: false
operators:
- registry: quay.io/okderators/catalog-index:testing-4.20 &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
packages:
- name: aws-load-balancer-operator
- name: 3scale-operator
- name: node-observability-operator
additionalImages:
- name: registry.redhat.io/ubi8/ubi:latest
- name: registry.redhat.io/ubi9/ubi@sha256:20f695d2a91352d4eaa25107535126727b5945bff38ed36a3e59590f495046f0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We used a minimal configuration without operators and additional images, because downloading additional images did not work for us:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;kind: ImageSetConfiguration
apiVersion: mirror.openshift.io/v2alpha1
mirror:
platform:
channels:
- name: 4-scos-stable &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
type: okd
minVersion: 4.21.0-okd-scos.3 &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
maxVersion: 4.21.0-okd-scos.3
graph: false
operators: []
additionalImages: []&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The hard part for us was finding the right values for &lt;em&gt;channels&lt;/em&gt; and
the min/max versions. Once again the OKD
&lt;a href="https://amd64.origin.releases.ci.openshift.org/"&gt;release status page&lt;/a&gt;
was helpful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Our private registry is based on &lt;a href="https://goharbor.io"&gt;Harbor&lt;/a&gt; for our
experiments, but any Docker v2 compatible registry should work. The
only thing required is a project within Harbor called &lt;em&gt;openshift&lt;/em&gt; and
a user/password for pulling/pushing images to this project. The
project name might be configurable with &lt;em&gt;oc mirror&lt;/em&gt;, but this requires
further investigation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;em&gt;oc mirror&lt;/em&gt; wants to verify signatures so we had to download a public
key and provide the &lt;em&gt;OCP_SIGNATURE_URL&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-shell hljs" data-lang="shell"&gt;curl -LO https://raw.githubusercontent.com/openshift/cluster-update-keys/master/keys/verifier-public-key-openshift-ci-4
export OCP_SIGNATURE_URL=&amp;#34;https://storage.googleapis.com/openshift-ci-release/releases/signatures/openshift/release/&amp;#34;
export OCP_SIGNATURE_VERIFICATION_PK=&amp;#34;verifier-public-key-openshift-ci-4&amp;#34;
# for debugging add --log-level debug, but we had intermittent errors with this option.
# after removing --log-level debug oc mirror ran without problems
oc mirror -c ImageSetConfiguration.yaml --authfile docker-auth.json --workspace file:///workspace docker://internal.registry --v2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This will create the &lt;em&gt;ImageDigestMirrorSource&lt;/em&gt; in &lt;em&gt;/workspace/working-dir/cluster-resources/idms-oc-mirror.yaml&lt;/em&gt; and &lt;em&gt;ImageTagMirrorSource&lt;/em&gt; custom resources in &lt;em&gt;/workspace/working-dir/cluster-resources/itms-oc-mirror.yaml&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The content of &lt;em&gt;ImageDigestMirrorSource&lt;/em&gt; will be reused in
the &lt;em&gt;install-config.yaml&lt;/em&gt;. This is required to redirect image pulls done by the node from &lt;em&gt;quay.io&lt;/em&gt; to our private registry.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Next we need DNS records for our cluster:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;api.sno.internal&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;api-int.sno.internal&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;*.apps.sno.internal (wildcard DNS entry for applications deployed on the cluster)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Now we prepared the required &lt;em&gt;install-config.yaml&lt;/em&gt; file to trigger the &lt;em&gt;openshift-install&lt;/em&gt; command.
We basically followed &lt;a href="https://docs.okd.io/latest/installing/installing_sno/install-sno-installing-sno.html"&gt;Installing a Single Node OpenShift Cluster&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: v1
baseDomain: internal
compute:
- hyperthreading: Enabled
name: worker
replicas: 0 &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
controlPlane:
hyperthreading: Enabled
name: master
replicas: 1 &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
metadata:
name: okd-sno
networking:
clusterNetwork:
- cidr: 10.128.0.0/14
hostPrefix: 23
networkType: OVNKubernetes
serviceNetwork:
- 172.30.0.0/16
platform:
none: {}
fips: false
sshKey: &amp;#39;the key&amp;#39;
bootstrapInPlace: &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
installationDisk: /dev/vda
pullSecret: |
{
&amp;#34;auths&amp;#34;: {
&amp;#34;registry.internal&amp;#34;: {
&amp;#34;auth&amp;#34;: &amp;#34;&amp;lt;username:password base64 encoded&amp;gt;&amp;#34;,
&amp;#34;email&amp;#34;: &amp;#34;some@email&amp;#34;
}
}
}
additionalTrustBundle: | &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
-----BEGIN CERTIFICATE-----
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
-----END CERTIFICATE-----
ImageDigestSources: &lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
- mirrors:
- registry.internal/openshift/release
source: quay.io/okd/scos-content
- mirrors:
- registry.internal/openshift/release-images
source: quay.io/okd/scos-release&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We set the number of workers to zero (0). Because this is a SNO installation. Worker nodes could be added later, even for a SNO cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We set the number of master nodes to one (1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;This tells the installer that we do not have a bootstrap node and it should create one large ignition config file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;If required the CA certificate of our registry. This is required if the registry uses an internal certificate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;ImageDigestSources configures CRIO to redirect requests to quay.io to our private registry.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;It’s time to create the installation manifests and ignition configs. We created a directory &lt;em&gt;install&lt;/em&gt;, copied the &lt;em&gt;install-config.yaml&lt;/em&gt; into this directory and triggered the &lt;em&gt;openshift-install&lt;/em&gt; command:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-shell hljs" data-lang="shell"&gt;$ mkdir install
$ cp install-config.yaml install/
$ openshift-install --dir=install create single-node-ignition-config&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We are now ready to download the installation ISO and to embed our ignition config into it. We also want
to set kernel boot arguments to configure the network interface with a static IP address.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-shell hljs" data-lang="shell"&gt;curl -L $( ./openshift-install coreos print-stream-json |jq -r &amp;#34;.architectures.x86_64.artifacts.metal.formats.iso.disk.location&amp;#34; ) -o fhcos-live.iso&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The next step is to modify the ISO. We basically followed the instructions in the OKD documentation:
&lt;a href="https://docs.okd.io/4.14/installing/installing_sno/install-sno-installing-sno.html#generating-the-install-iso-manually_install-sno-installing-sno-with-the-assisted-installer" class="bare"&gt;https://docs.okd.io/4.14/installing/installing_sno/install-sno-installing-sno.html#generating-the-install-iso-manually_install-sno-installing-sno-with-the-assisted-installer&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-shell hljs" data-lang="shell"&gt;alias coreos-installer=&amp;#39;podman run --privileged --pull always --rm -v /dev:/dev -v /run/udev:/run/udev -v $PWD:/data -w /data quay.io/coreos/coreos-installer:release&amp;#39;
coreos-installer iso ignition embed -fi install/bootstrap-in-place-for-live-iso.ign fcos-live.iso
coreos-installer iso kargs modify --append &amp;#39;ip=10.0.0.99::10.0.0.1:255.255.255.0:sno.internal:ens33:none:10.0.0.255&amp;#39; fcos-live.iso&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We can take a look at the ISO bootstrap config and the kernel arguments with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;coreos-installer iso ignition show fcos-live.iso
coreos-installer iso kargs show fcos-live.iso&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;For understanding the kernel boot arguments see &lt;a href="https://access.redhat.com/solutions/5499911" class="bare"&gt;https://access.redhat.com/solutions/5499911&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The final step is to boot the modified ISO on the target machine and wait for the installation to complete.&lt;/p&gt;
&lt;/div&gt;</description></item><item><title>What's new in OpenShift, 4.20 Edition</title><link>https://blog.stderr.at/whats-new/2025-11-10-whatsnew-420/</link><pubDate>Mon, 10 Nov 2025 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/whats-new/2025-11-10-whatsnew-420/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;This article covers news and updates in the OpenShift 4.20 release. We focus on points that got our attention, but this
is &lt;strong&gt;not&lt;/strong&gt; a complete summary of the &lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/release_notes/index"&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_configuring_a_local_arbiter_node"&gt;Configuring a local arbiter node&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/installing_an_on-premise_cluster_with_the_agent-based_installer/index#installing-ocp-agent-local-arbiter-node_installing-with-agent-based-installer"&gt;Configuring a local arbiter node&lt;/a&gt; describes how to configure an OCP cluster with only two control plane (ETCD) nodes. Might be useful in a pure bare metal environment where three bare metal control plane nodes might be overkill.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_two_node_clusters_with_fencing"&gt;Two node clusters with fencing&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/installing_on_bare_metal/index#bmo-about-the-hostfirmwarecomponents-resource_bare-metal-postinstallation-configuration"&gt;Two-node with Fencing&lt;/a&gt; still in tech preview. Useful for environments with only two active datacenters. Especially if you have bare metal control plane nodes. We got quite a few customers with only to data centers available.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_about_the_hostfirmwarecomponents_resource"&gt;About the HostFirmwareComponents resource&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/installing_on_bare_metal/index#bmo-about-the-hostfirmwarecomponents-resource_bare-metal-postinstallation-configuration"&gt;About the HostFirmwareComponents&lt;/a&gt;. When Metal3 is used it’s now possible to update the NIC (Network interface card) firmware.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_boot_image_updates_on_vmware"&gt;Boot image updates on Vmware&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/machine_configuration/index#mco-update-boot-images"&gt;Boot image management&lt;/a&gt; can be used to update the boot image for new nodes. Up until now
when you installed you cluster on VMware with a certain boot image (let’s say 4.15) it never got updates. New nodes were always booted from this old image and later updated to the current cluster release.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_about_on_cluster_image_mode"&gt;About on-cluster image mode&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/machine_configuration/index#coreos-layering-configuring-on_mco-coreos-layering"&gt;About on-cluster image mode&lt;/a&gt;. Image mode allows you to customize the node operating system image. You basically create a Containerfile, install custom RPM’s or deploy custom configuration files in the Containerfile and OCP creates a layered image for you cluster. The image is automatically rolled out to the cluster with the Machine Config Operator. Fancy stuff…​.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_pinning_images"&gt;Pinning images&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/machine_configuration/index#machine-config-pin-preload-images_machine-config-operator"&gt;Pinning images&lt;/a&gt;. If your internet connection is flaky, or you have reasons to not trust the availablity of Red Hat registries like quay.io or registry.redhat.io you can now pin images those images. They are pulled down immediately and will not be garbage collected (hopefully…​).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_bgp_routing"&gt;BGP routing&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/advanced_networking/index#about-bgp-routing"&gt;About BGP routing&lt;/a&gt;. MetalLB had support for announcing IP’s via BGP for a long time, but now it’s also possible to announce UDN’s or EgressIP. IMHO this is especially interesting for EgressIP because there were some nasty &lt;a href="https://issues.redhat.com/browse/OCPBUGS-42303"&gt;bugs&lt;/a&gt; around using &lt;a href="https://wiki.wireshark.org/Gratuitous_ARP"&gt;GRAP (Gratuitous ARP)&lt;/a&gt; for announcing IP’s to switches.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_migrating_a_configured_br_ex_bridge_to_nmstate"&gt;Migrating a configured br-ex bridge to NMState&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/installing_on_bare_metal/index#migrating-br-ex-bridge-nmstate_bare-metal-postinstallation-configuration"&gt;Migrating a configured br-ex bridge to NMState&lt;/a&gt;. There’s this ominous &lt;em&gt;configure-ovs.sh&lt;/em&gt; that reconfigures the public interface of a node an brings up br-ex. There was support for deploying an NMState-based configuration during cluster installation and not using &lt;em&gt;configure-ovs.sh&lt;/em&gt;. Now it’s also possible to get rid of the shell script &lt;strong&gt;after&lt;/strong&gt; installation.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_configuration_for_a_bond_cni_secondary_network"&gt;Configuration for a Bond CNI secondary network&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/multiple_networks/index#nw-multus-bond-cni-object_configuring-additional-network-cni"&gt;Configuration for a Bond CNI secondary network&lt;/a&gt;. Bond interface can now be created for interface in containers. This currently only supports SR-IOV virtual functions.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_manage_secure_signatures_with_sigstore"&gt;Manage secure signatures with sigstore&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/nodes/index#nodes-sigstore-using"&gt;Manage secure signatures with sigstore&lt;/a&gt;. Sigstore support can now be enabled on a cluster level or on an individual namespace level.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_running_pods_in_linux_user_namespaces"&gt;Running pods in Linux user namespaces&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/nodes/index#nodes-pods-user-namespaces"&gt;Running pods in Linux user namespaces&lt;/a&gt;. This is IMHO a big one. Linux user namespaces are finally supported in OpenShift! So it’s possible to grant root inside a container and map the root UID to an unprivileged ID outside the container.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_adjust_pod_resource_levels_without_pod_disruption"&gt;Adjust pod resource levels without pod disruption&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/nodes/index#nodes-pods-adjust-resources-in-place"&gt;Adjust pod resource levels without pod disruption&lt;/a&gt;. Resize CPU and memory resource without restarting a Pod!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_introducing_the_oc_adm_upgrade_recommend_command_general_availability"&gt;Introducing the &lt;em&gt;oc adm upgrade recommend&lt;/em&gt; command (General Availability)&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/updating_clusters/index#understanding-openshift-updates"&gt;Understanding OpenShift upgrades&lt;/a&gt;. &lt;em&gt;oc&lt;/em&gt; know officially supports cluster upgrade from the command line. &lt;em&gt;oc adm upgrade recommended&lt;/em&gt; performs some pre-flight checks before upgrading a cluster.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_additional_cluster_latency_requirements_for_etcd"&gt;Additional cluster latency requirements for etcd&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html-single/etcd/index#recommended-cluster-latency-etcd_etcd-practices"&gt;Cluster latency requirements for etcd&lt;/a&gt;. ETCD latency requirements were updated in the documentation.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_sunset_of_the_red_hat_marketplace_operated_by_ibm"&gt;Sunset of the Red Hat Marketplace, operated by IBM&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://access.redhat.com/articles/7130828"&gt;Sunset of the Red Hat Marketplace, operated by IBM&lt;/a&gt;. It seems Red Hat Marktplace is no more…​&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_how_to_use_changed_block_tracking_dev_preview_in_openshift_4_20"&gt;How to use Changed Block Tracking (Dev Preview) in OpenShift 4.20&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;a href="https://access.redhat.com/solutions/7131061"&gt;How to use Changed Block Tracking (Dev Preview) in OpenShift 4.20&lt;/a&gt;. Change block tracking for PV’s is now in dev preview. Whatever this means exactly, needs more investigation.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>A second look into the Kubernetes Gateway API on OpenShift</title><link>https://blog.stderr.at/openshift-platform/networking/2025-08-31-openshift-gateway-api-ii/</link><pubDate>Sun, 31 Aug 2025 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/networking/2025-08-31-openshift-gateway-api-ii/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;This is our second look into the Kubernetes Gateway API an it’s
integration into OpenShift. This post covers TLS configuration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The Kubernetes Gateway API is new implementation of the ingress, load
balancing and service mesh API’s. See
&lt;a href="https://gateway-api.sigs.k8s.io/" target="_blank" rel="noopener"&gt;upstream&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Also the &lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html/ingress_and_load_balancing/configuring-ingress-cluster-traffic#nw-ingress-gateway-api-overview_ingress-gateway-api" target="_blank" rel="noopener"&gt;OpenShift documentation&lt;/a&gt; provides an overview of the Gateway API and it’s integration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We demonstrate how to add TLS to our Nginx deployment, how to
implement a shared Gateway and finally how to implement HTTP to HTTPS
redirection with the Gateway API. Furthermore we cover how &lt;em&gt;HTTPRoute&lt;/em&gt;
objects attach to Gateways and dive into ordering of &lt;em&gt;HTTPRoute&lt;/em&gt;
objects.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock warning"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-warning" title="Warning"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
b2cc commented that deploying the gateway in the
&lt;em&gt;openshift-ingress&lt;/em&gt; namespace, as we did below, is not support by
Red Hat. We are not aware this is documented somewhere (please let use
now if it is). Only after opening a support ticket he learned that
this not supported. We will keep the examples below as they are, so
be careful and this may eat your cat.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_references"&gt;References&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.stderr.at/openshift/2025/08/gateway-api/"&gt;A first look into the Kubernetes Gateway API on OpenShift&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_adding_tls_to_our_nginx_deployment"&gt;Adding TLS to our Nginx deployment&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In our fist post we simply exposed a Nginx web server via the
Gateway API. We only enabled HTTP, so let’s try to do the same with
HTTPS now.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Remember we use a DNS wildcard domain &lt;code&gt;*.gtw.ocp.lan.stderr.at&lt;/code&gt; which
points to our Gateway. The gateway is exposed via a &lt;em&gt;Service&lt;/em&gt; of type
&lt;em&gt;LoadBalancer&lt;/em&gt;. We use
&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html/networking_operators/metallb-operator"&gt;MetalLB&lt;/a&gt;
for this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The first step is setting up a wildcard TLS certificate for our custom
domain &lt;em&gt;*.gtw.ocp.lan.stderr.at&lt;/em&gt;. We are using
&lt;a href="https://github.com/OpenVPN/easy-rsa"&gt;EasyRSA&lt;/a&gt; here, but use whatever tool you like.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Just for reference this is how we created a wildcard cert with EasyRSA:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ EASYRSA_CERT_EXPIRE=3650 EASYRSA_EXTRA_EXTS=&amp;#34;subjectAltName=DNS:*.gtw.ocp.lan.stderr.at&amp;#34; ./easyrsa gen-req gtw.ocp.lan.stderr.at
$ EASYRSA_CERT_EXPIRE=3650 ./easyrsa sign-req serverClient gtw.ocp.lan.stderr.at&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;EasyRSA stores the public key under &lt;em&gt;pki/issued&lt;/em&gt; and the private key
under &lt;em&gt;pki/private&lt;/em&gt;. We copied the certificate and the private key to
a temporary directory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Next we need to remove the private key passphrase and create a
Kubernetes secret from the private and pubic key:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ openssl rsa -in gtw.ocp.lan.stderr.at.key -out gtw.ocp.lan.stderr.at-insecure.key
$ oc create secret -n openshift-ingress tls gateway-api --cert=gtw.ocp.lan.stderr.at.crt --key=gtw.ocp.lan.stderr.at-insecure.key&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Now it’s time to add a TLS listener to our &lt;em&gt;Gateway&lt;/em&gt; resource in the
&lt;em&gt;openshift-ingress&lt;/em&gt; namespace. Remember for the OpenShift Gateway API implementation, &lt;em&gt;Gateways&lt;/em&gt; have
to be deployed in the &lt;em&gt;openshift-ingress&lt;/em&gt; namespace.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http-gateway
namespace: openshift-ingress
spec:
gatewayClassName: openshift-default
listeners:
- name: http
protocol: HTTP
port: 80
hostname: &amp;#34;*.gtw.ocp.lan.stderr.at&amp;#34;
- name: https
protocol: HTTPS &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
port: 443 &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
hostname: &amp;#34;*.gtw.ocp.lan.stderr.at&amp;#34; &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
tls:
mode: Terminate &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
certificateRefs:
- name: gateway-api &lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
allowedRoutes: &lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
namespaces:
from: All&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We want to support HTTPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We use the default HTTPS port 443&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The URLs we support with this listener are the same as for HTTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We use edge termination for now, this means HTTP traffic will only be encrypted up to the gateway. From the gateway to our pod we speak plain HTTP.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="5"&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;This is the name of the TLS secret we created above&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="6"&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We accept routes from all namespaces&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Also remember from our first post that we created a
&lt;em&gt;ReferenceGrant&lt;/em&gt; in the namespace where Nginx is running. Otherwise
HTTP routes will not be accepted.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Finally lets try to access our Nginx pod via HTTPS:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ curl -v https://nginx.gtw.ocp.lan.stderr.at
* Host nginx.gtw.ocp.lan.stderr.at:443 was resolved.
* IPv6: (none)
* IPv4: 10.0.0.150
* Trying 10.0.0.150:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
* CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / x25519 / RSASSA-PSS
* ALPN: server accepted h2
* Server certificate:
* subject: CN=gtw.ocp.lan.stderr.at
* start date: Aug 30 10:01:33 2025 GMT
* expire date: Aug 28 10:01:33 2035 GMT
* subjectAltName: host &amp;#34;nginx.gtw.ocp.lan.stderr.at&amp;#34; matched cert&amp;#39;s &amp;#34;*.gtw.ocp.lan.stderr.at&amp;#34;
* issuer: CN=tntinfra CA
* SSL certificate verify ok.
* Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Connected to nginx.gtw.ocp.lan.stderr.at (10.0.0.150) port 443
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://nginx.gtw.ocp.lan.stderr.at/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: nginx.gtw.ocp.lan.stderr.at]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.11.1]
* [HTTP/2] [1] [accept: */*]
&amp;gt; GET / HTTP/2
&amp;gt; Host: nginx.gtw.ocp.lan.stderr.at
&amp;gt; User-Agent: curl/8.11.1
&amp;gt; Accept: */*
&amp;gt;
* Request completely sent off
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
&amp;lt; HTTP/2 200
&amp;lt; server: nginx/1.29.1
&amp;lt; date: Sat, 30 Aug 2025 14:30:20 GMT
&amp;lt; content-type: text/html
&amp;lt; content-length: 615
&amp;lt; last-modified: Wed, 13 Aug 2025 14:33:41 GMT
&amp;lt; etag: &amp;#34;689ca245-267&amp;#34;
&amp;lt; accept-ranges: bytes
(output omitted)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Yes, we can reach our Nginx via HTTPS, and the gateway presents the TLS certificate we created.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Be aware that we are still using the same &lt;em&gt;HTTPRoute&lt;/em&gt; for Nginx from our previous blog post.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Just for completeness here is the &lt;em&gt;HTTPRoute&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: nginx-route
spec:
parentRefs:
- name: http-gateway
namespace: openshift-ingress
hostnames: [&amp;#34;nginx.gtw.ocp.lan.stderr.at&amp;#34;]
rules:
- backendRefs:
- name: nginx
namespace: gateway-api-test
port: 8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Also Remember that we are using a dedicated &lt;em&gt;Gateway&lt;/em&gt; and all
&lt;em&gt;HTTPRoutes&lt;/em&gt; must be in the namespace &lt;em&gt;openshift-ingress&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_moving_to_a_shared_gateway"&gt;Moving to a shared gateway&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Up until now we had to create all &lt;em&gt;HTTPRoute&lt;/em&gt; objects in the
&lt;em&gt;openshift-ingress&lt;/em&gt; namespace. The Gateway API support two modes of
operations:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Dedicated gateway: all &lt;em&gt;HTTPRoute&lt;/em&gt; object need to be in the same namespace as the gateway&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Shared gateway: The gateway runs in the &lt;em&gt;openshift-ingress&lt;/em&gt;
namespace and we allow &lt;em&gt;HTTPRoute&lt;/em&gt; objects from all or specific namespaces.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The first step in creating a shared gateway is to modify the gateway resource:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http-gateway
namespace: openshift-ingress
spec:
gatewayClassName: openshift-default
listeners:
- name: http
protocol: HTTP
port: 80
hostname: &amp;#34;*.gtw.ocp.lan.stderr.at&amp;#34;
allowedRoutes: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
namespaces:
from: All&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We now allow &lt;em&gt;HTTPRoute&lt;/em&gt; objects from all namespaces in the cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Next we delete the existing &lt;em&gt;HTTPRoute&lt;/em&gt; for Nginx in the
&lt;em&gt;openshift-ingress&lt;/em&gt; namespaces, and verify that we can’t reach Nginx:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc delete httproutes.gateway.networking.k8s.io -n openshift-ingress nginx-route
httproute.gateway.networking.k8s.io &amp;#34;nginx-route&amp;#34; deleted
$ curl -I http://nginx.gtw.ocp.lan.stderr.at
HTTP/1.1 404 Not Found &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
date: Sat, 30 Aug 2025 15:02:23 GMT
transfer-encoding: chunked&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Our Nginx route stopped working&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Next we apply our modified &lt;em&gt;Gateway&lt;/em&gt; resource in the
&lt;em&gt;openshift-ingress&lt;/em&gt; namespace and the &lt;em&gt;HTTPRoute&lt;/em&gt; object in the
&lt;em&gt;gateway-api-test&lt;/em&gt; namespace.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc apply -n openshift-ingress -f gateway--selector.yaml
gateway.gateway.networking.k8s.io/http-gateway configured
$ oc apply -n gateway-api-test -f httproute.yaml &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
httproute.gateway.networking.k8s.io/nginx-route created
$ curl -I http://nginx.gtw.ocp.lan.stderr.at
HTTP/1.1 200 OK &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
server: nginx/1.29.1
date: Sat, 30 Aug 2025 15:04:34 GMT
content-type: text/html
content-length: 615
last-modified: Wed, 13 Aug 2025 14:33:41 GMT
etag: &amp;#34;689ca245-267&amp;#34;
accept-ranges: bytes&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We create the &lt;em&gt;HTTPRoute&lt;/em&gt; in the gateway-api-test namespace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We can reach our Nginx pod again&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So our shared gateway seems to be working. But what if we want to
restrict which namespaces are allowed to create route objects?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The Gateway API allows the following settings under &lt;em&gt;spec.listeners[].allowedRoutes.namespaces.from&lt;/em&gt; field&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;All&lt;/strong&gt;: Allow from all namespaces&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Selector&lt;/strong&gt;: Specify a selector&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Same&lt;/strong&gt;: Only allow &lt;em&gt;HTTPRoutes&lt;/em&gt; in the same namespaces&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;None&lt;/strong&gt;: Do not allow any routes to attach&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;See the API specification &lt;a href="https://gateway-api.sigs.k8s.io/reference/spec/#fromnamespaces"&gt;FromNamespaces&lt;/a&gt; for details.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s try to use a more specific selector for our gateway:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http-gateway
namespace: openshift-ingress
spec:
gatewayClassName: openshift-default
listeners:
- name: http
protocol: HTTP
port: 80
hostname: &amp;#34;*.gtw.ocp.lan.stderr.at&amp;#34;
allowedRoutes:
namespaces:
from: Selector &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
selector:
matchLabels:
kubernetes.io/metadata.name: gateway-api-test &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Now we are using the Selector option&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Because we do not have a specific label on the namespace we would like to use, let’s use the &lt;em&gt;metadata.name&lt;/em&gt; label Kubernetes created for us&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We create a new yaml file &lt;em&gt;gateway-selector.yaml&lt;/em&gt; and appy the new configuration:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc apply -n openshift-ingress -f gateway-selector.yaml
gateway.gateway.networking.k8s.io/http-gateway configured
$ curl -I http://nginx.gtw.ocp.lan.stderr.at
HTTP/1.1 200 OK
server: nginx/1.29.1
date: Sat, 30 Aug 2025 15:17:17 GMT
content-type: text/html
content-length: 615
last-modified: Wed, 13 Aug 2025 14:33:41 GMT
etag: &amp;#34;689ca245-267&amp;#34;
accept-ranges: bytes&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;All good, still working.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Just for testing we modified the namespace name in the Gateway definition to &lt;strong&gt;NOT&lt;/strong&gt; match the namespace of our Nginx deployment and confirmed that we receive a &lt;em&gt;404&lt;/em&gt; not found response.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_implementing_http_to_https_redirect"&gt;Implementing HTTP to HTTPS redirect&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;As a last test for this post let’s try to implement HTTP to HTTPS redirects.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We deployed the following &lt;em&gt;Gateway&lt;/em&gt; configuration:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http-gateway
namespace: openshift-ingress &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
spec:
gatewayClassName: openshift-default
listeners:
- name: http
protocol: HTTP
port: 80
hostname: &amp;#34;*.gtw.ocp.lan.stderr.at&amp;#34;
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
kubernetes.io/metadata.name: gateway-api-test2
- name: https &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
protocol: HTTPS
port: 443
hostname: &amp;#34;*.gtw.ocp.lan.stderr.at&amp;#34;
tls:
mode: Terminate
certificateRefs:
- name: gateway-api
allowedRoutes:
namespaces:
from: All&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Always deploy the gateway to the &lt;em&gt;openshift-ingress&lt;/em&gt; namespace for the OpenShift Gateway API implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We added the HTTPS configuration back&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The &lt;a href="https://gateway-api.sigs.k8s.io/guides/http-redirect-rewrite/"&gt;upstream&lt;/a&gt; documentation contains an example on how to implements HTTP to HTTPS redirects. We created the following additional &lt;em&gt;HTTPRoute&lt;/em&gt; object in the &lt;em&gt;gateway-api-test&lt;/em&gt; namespace:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-https-redirect
spec:
parentRefs:
- name: http-gateway &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
namespace: openshift-ingress
sectionName: http &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
hostnames:
- nginx.gtw.ocp.lan.stderr.at
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Match our &lt;em&gt;Gateway&lt;/em&gt; &lt;em&gt;http-gateway&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Match the &lt;em&gt;http&lt;/em&gt; section in our gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Just for reference this is the &lt;em&gt;HTTPRoute&lt;/em&gt; object to expose Nginx:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: nginx-route
spec:
parentRefs:
- name: http-gateway
namespace: openshift-ingress
hostnames: [&amp;#34;nginx.gtw.ocp.lan.stderr.at&amp;#34;]
rules:
- backendRefs:
- name: nginx
namespace: gateway-api-test
port: 8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;First we re-applied our &lt;em&gt;Gateway&lt;/em&gt; configuration&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc apply -f gateway-https-selector.yaml
gateway.gateway.networking.k8s.io/http-gateway configured&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s try and verify if our redirect is working, we need to apply both routes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc apply -f httproute.yaml
httproute.gateway.networking.k8s.io/nginx-route created
$ oc apply -f http-https-redirect-route.yaml
httproute.gateway.networking.k8s.io/http-https-redirect created&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;And test with curl:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ curl -I http://nginx.gtw.ocp.lan.stderr.at
HTTP/1.1 200 OK &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
server: nginx/1.29.1
date: Sat, 30 Aug 2025 15:37:20 GMT
content-type: text/html
content-length: 615
last-modified: Wed, 13 Aug 2025 14:33:41 GMT
etag: &amp;#34;689ca245-267&amp;#34;
accept-ranges: bytes&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Hm, strange we still get 200 OK and &lt;strong&gt;NOT&lt;/strong&gt; a redirect to HTTPS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_understanding_httproute_ordering"&gt;Understanding HTTPRoute ordering&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;After a longer search through the documentation we found some hints on why this is happening.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s take a more detailed look at our http-to-https route again, as a
&lt;em&gt;HTTPRoute&lt;/em&gt; &lt;strong&gt;attaches&lt;/strong&gt; to a &lt;em&gt;Gateway&lt;/em&gt;, we focus on the &lt;em&gt;parentRefs&lt;/em&gt; in
the &lt;em&gt;HTTPRoute&lt;/em&gt; object. In our current understanding &lt;em&gt;parentRefs&lt;/em&gt; select a &lt;em&gt;Gateway&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-https-redirect
spec:
parentRefs: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
- name: http-gateway &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
namespace: openshift-ingress &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
sectionName: http &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
hostnames:
- nginx.gtw.ocp.lan.stderr.at
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Ok, this is the &lt;em&gt;parentRefs&lt;/em&gt; section we are looking for&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;name&lt;/em&gt; selects the name of the &lt;em&gt;Gateway&lt;/em&gt; we want to attach to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;namespace&lt;/em&gt; specifies the namespace where we can find the &lt;em&gt;Gateway&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;sectionName&lt;/em&gt; selects the section in the &lt;em&gt;Gateway&lt;/em&gt; where we want to attach to.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So this &lt;em&gt;HTTPRoute&lt;/em&gt; explicitly attaches to a &lt;em&gt;Gateway&lt;/em&gt; in a
&lt;em&gt;Namespace&lt;/em&gt; that has a &lt;em&gt;Section&lt;/em&gt; http defined.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If you look at the Gateway configuration above you will see that we
have a section for HTTP traffic and one for HTTPS traffic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s compare this with our Nginx &lt;em&gt;HTTPRoute&lt;/em&gt; definition:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: nginx-route
spec:
parentRefs: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
- name: http-gateway &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
namespace: openshift-ingress &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
hostnames: [&amp;#34;nginx.gtw.ocp.lan.stderr.at&amp;#34;]
rules:
- backendRefs:
- name: nginx
namespace: gateway-api-test
port: 8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The &lt;em&gt;parentRefs&lt;/em&gt; section&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The &lt;em&gt;Gateway&lt;/em&gt; we would like to attach to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The &lt;em&gt;namespace&lt;/em&gt; where the &lt;em&gt;Gateway&lt;/em&gt; is deploy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Note that &lt;em&gt;Section&lt;/em&gt; is missing in this configuration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So this &lt;em&gt;HTTPRoute&lt;/em&gt; actually attaches to &lt;strong&gt;both&lt;/strong&gt; sections in our
&lt;em&gt;Gateway&lt;/em&gt; definition, HTTP and HTTPS. Which is not what we want.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When a client hits the HTTP endpoint we want to redirect the traffic to HTTPS&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When a client hits the HTTPS endpoint we want the traffic to be forward to our Nginx deployment&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We found the following statement
&lt;a href="https://gateway-api.sigs.k8s.io/reference/spec/#httprouterule"&gt;statement&lt;/a&gt;
how ordering works in the Gateway API:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre&gt;If ties still exist across multiple Routes, matching precedence MUST be
determined in order of the following criteria, continuing on ties:
The oldest Route based on creation timestamp.&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;When we look at the timestamps of our &lt;em&gt;HTTPRoutes&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;oc get httproute -o jsonpath=&amp;#39;{range .items[*]}{.metadata.name}{&amp;#34;\t&amp;#34;}{.metadata.creationTimestamp}{&amp;#34;\n&amp;#34;}{end}&amp;#39;
http-https-redirect 2025-08-31T09:17:46Z &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
nginx-route 2025-08-31T09:17:40Z &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Creation timestamp of the redirect route&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Creation timestamp of the nginx route&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The Nginx &lt;em&gt;HTTPRoute&lt;/em&gt; is &lt;strong&gt;older&lt;/strong&gt; than the HTTP-to-HTTP &lt;em&gt;HTTPRoute&lt;/em&gt;. So
this matches first and a 200 OK is returned.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So let’s try to revers how we applied our &lt;em&gt;HTTPRoutes&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc delete httproutes.gateway.networking.k8s.io --all
httproute.gateway.networking.k8s.io &amp;#34;http-https-redirect&amp;#34; deleted
httproute.gateway.networking.k8s.io &amp;#34;nginx-route&amp;#34; deleted
$ oc apply -f http-to-https-httproute.yaml
httproute.gateway.networking.k8s.io/http-https-redirect created
$ oc apply -f nginx-httproute.yaml
httproute.gateway.networking.k8s.io/nginx-route created
$ oc get httproute -o jsonpath=&amp;#39;{range .items[*]}{.metadata.name}{&amp;#34;\t&amp;#34;}{.metadata.creationTimestamp}{&amp;#34;\n&amp;#34;}{end}&amp;#39;
http-https-redirect 2025-08-31T10:34:55Z &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
nginx-route 2025-08-31T10:35:11Z &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Creation timestamp of the HTTP-to-HTTPS route&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Creation timestamp of the nginx route&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Now the HTTP-to-HTTPS route is the oldest route. Let’s try again calling Nginx with curl:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ curl -I http://nginx.gtw.ocp.lan.stderr.at
HTTP/1.1 301 Moved Permanently &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
location: https://nginx.gtw.ocp.lan.stderr.at/
date: Sun, 31 Aug 2025 10:37:13 GMT
transfer-encoding: chunked
$ curl -I https://nginx.gtw.ocp.lan.stderr.at
HTTP/2 200 &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
server: nginx/1.29.1
date: Sun, 31 Aug 2025 10:37:17 GMT
content-type: text/html
content-length: 615
last-modified: Wed, 13 Aug 2025 14:33:41 GMT
etag: &amp;#34;689ca245-267&amp;#34;
accept-ranges: bytes&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The HTTP endpoint returns a redirect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;the HTTPS endpoint returns 200 OK from Nginx&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So now we have the expected behavior: HTTP is redirect to HTTPS!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;As depending on the time when an object is created is definitely &lt;strong&gt;NOT&lt;/strong&gt;
a good idea, let’s be more specific in our Nginx &lt;em&gt;HTTPRoute&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: nginx-route
spec:
parentRefs:
- name: http-gateway
namespace: openshift-ingress
sectionName: https &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
hostnames: [&amp;#34;nginx.gtw.ocp.lan.stderr.at&amp;#34;]
rules:
- backendRefs:
- name: nginx
namespace: gateway-api-test
port: 8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We explicitly select the &lt;strong&gt;HTTPS&lt;/strong&gt; section in our &lt;em&gt;Gateway&lt;/em&gt; configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Next we delete our &lt;em&gt;HTTPRoutes&lt;/em&gt; again, and re-apply them in the order that didn’t work the first time (Nginx is the oldest route):&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc delete httproutes.gateway.networking.k8s.io --all
httproute.gateway.networking.k8s.io &amp;#34;http-https-redirect&amp;#34; deleted
httproute.gateway.networking.k8s.io &amp;#34;nginx-route&amp;#34; deleted
$ oc apply -f http-to-https-httproute.yaml
httproute.gateway.networking.k8s.io/http-https-redirect created
$ oc get httproute -o jsonpath=&amp;#39;{range .items[*]}{.metadata.name}{&amp;#34;\t&amp;#34;}{.metadata.creationTimestamp}{&amp;#34;\n&amp;#34;}{end}&amp;#39;
http-https-redirect 2025-08-31T10:45:01Z
nginx-route 2025-08-31T10:44:57Z &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
$ curl -I http://nginx.gtw.ocp.lan.stderr.at
HTTP/1.1 301 Moved Permanently &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
location: https://nginx.gtw.ocp.lan.stderr.at/
date: Sun, 31 Aug 2025 10:46:22 GMT
transfer-encoding: chunked
$ curl -I https://nginx.gtw.ocp.lan.stderr.at
HTTP/2 200 &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
server: nginx/1.29.1
date: Sun, 31 Aug 2025 10:46:30 GMT
content-type: text/html
content-length: 615
last-modified: Wed, 13 Aug 2025 14:33:41 GMT
etag: &amp;#34;689ca245-267&amp;#34;
accept-ranges: bytes&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The Nginx route is the oldest route&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The HTTP endpoint returns a redirect to HTTPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The response from our Nginx deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Finally everything works as expected!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
A &lt;em&gt;HTTPRoute&lt;/em&gt; attaches to a &lt;em&gt;Gateway&lt;/em&gt;. Always be as specific as
possible which &lt;em&gt;Gateway&lt;/em&gt; to match and which &lt;em&gt;section&lt;/em&gt; in the
&lt;em&gt;Gateway&lt;/em&gt;.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In this blog post we demonstrated to implement TLS with the
Gateway API. We also implemented a shared &lt;em&gt;Gateway&lt;/em&gt; with &lt;em&gt;HTTPRoute&lt;/em&gt;
objects in different namespaces.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Furthermore we configured HTTP to HTTPS redirects and dove into
&lt;em&gt;HTTPRoute&lt;/em&gt; ordering if a route matches multiple listeners in a
&lt;em&gt;Gateway&lt;/em&gt; definition.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>A first look into the Kubernetes Gateway API on OpenShift</title><link>https://blog.stderr.at/openshift-platform/networking/2025-08-29-openshift-gateway-api/</link><pubDate>Fri, 29 Aug 2025 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/networking/2025-08-29-openshift-gateway-api/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;This blog post summarizes our first look into the Kubernetes Gateway
API and how it is integrated in OpenShift.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The Kubernetes Gateway API is new implementation of the ingress, load
balancing and service mesh API’s. See
&lt;a href="https://gateway-api.sigs.k8s.io/" target="_blank" rel="noopener"&gt;upstream&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Also the &lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html/ingress_and_load_balancing/configuring-ingress-cluster-traffic#nw-ingress-gateway-api-overview_ingress-gateway-api" target="_blank" rel="noopener"&gt;OpenShift documentation&lt;/a&gt; provides an overview of the Gateway API and it’s integration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_things_to_consider_when_using_gateway_api_with_openshift"&gt;Things to consider when using Gateway API with OpenShift&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Currently UDN (User Defined Networks) with Gateway API are not supported.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Only TLS termination on the edge is supported (no pass-through or re-encrypt), this needs to be confirmed. We can’t find the original source of this statement&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The standard OpenShift ingress controller manages Gateway API Resources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gateway API provides a standard on how to get client traffic into a
Kubernetes cluster. Vendors provide an implementation of the API. So
OpenShift provides &lt;strong&gt;ONE&lt;/strong&gt; possible implementation, but there could
be more than one in a cluster.&lt;/p&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We found the following sentence in the OpenShift documentation
interesting:&lt;/p&gt;
&lt;div class="literalblock"&gt;
&lt;div class="content"&gt;
&lt;pre&gt;Because OpenShift Container Platform uses a specific
version of Gateway API CRDs, any use of third-party implementations
of Gateway API must conform to the OpenShift Container Platform
implementation to ensure that all fields work as expected&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_setting_up_gateway_api_on_openshift"&gt;Setting up Gateway API on OpenShift&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Before you begin, ensure you have the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;OpenShift 4.19 or higher with cluster-admin access&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;First you need to create a &lt;code&gt;GatewayClass&lt;/code&gt; object.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Be aware that the &lt;code&gt;GatewayClass&lt;/code&gt; object is &lt;strong&gt;NOT&lt;/strong&gt; namespaced.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: openshift-default
spec:
controllerName: openshift.io/gateway-controller/v1 &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The controller name needs to be exactly as shown. Otherwise the
ingress controller will &lt;strong&gt;NOT&lt;/strong&gt; manage the gateway and associated
resources.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This creates a new pod in the openshift-ingress namespace:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc get po -n openshift-ingress
NAME READY STATUS RESTARTS AGE
istiod-openshift-gateway-7b567bc8b4-4lrt2 1/1 Running 0 12m &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
router-default-6db958cbd-dlbwz 1/1 Running 12 14d&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;this pod got create after applying the gateway class resource&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;code&gt;router-default&lt;/code&gt; is the default openshift ingress pod. The first
difference seems to be the SCC (security context constraint) the pods
are using.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc get po -n openshift-ingress -o jsonpath=&amp;#39;{range .items[*]}{.metadata.name}{&amp;#34;\t&amp;#34;}{.metadata.annotations.openshift\.io/scc}{&amp;#34;\n&amp;#34;}{end}&amp;#39;
istiod-openshift-gateway-7b567bc8b4-4lrt2 restricted-v2
router-default-6db958cbd-dlbwz hostnetwork&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The standard router used host networking for listing on port 80 and 443
on the node where it is running. Our &lt;code&gt;GatewayClass&lt;/code&gt; currently only
provides a pod running Istiod awaiting further configuration. To
actually listen for client request additional configuration is
required.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;A &lt;code&gt;Gateway&lt;/code&gt; is required to listen for client requests. We create the
following gateway:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http-gateway
namespace: openshift-ingress &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
spec:
gatewayClassName: openshift-default
listeners:
- name: http
protocol: HTTP
port: 80
hostname: &amp;#34;*.apps.ocp.lan.stderr.at&amp;#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We create this gateway in the same namespace as the istio
deployment. This is required for OpenShift.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This creates an additional pod in the &lt;code&gt;openshift-ingress&lt;/code&gt; namespace:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc get po
NAME READY STATUS RESTARTS AGE
http-gateway-openshift-default-d476664f5-h87mp 1/1 Running 0 36s&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We also got a new service for the our http-gateway&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;➜ oc get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-gateway-openshift-default LoadBalancer 172.30.183.48 10.0.0.150 15021:30251/TCP,80:30437/TCP 4m52s&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The interesting thing is the &lt;code&gt;TYPE&lt;/code&gt; of the service. It’s of type
&lt;code&gt;LoadBalancer&lt;/code&gt;. We have
&lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html/networking_operators/metallb-operator"&gt;MetalLB&lt;/a&gt;
deployed in our cluster, this might be the reason for this. We will
try to configure a gateway without MetalLB in in upcoming post.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Lets take a look at the gateway resource&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc get gtw
NAME CLASS ADDRESS PROGRAMMED AGE
http-gateway openshift-default 10.0.0.150 True 3m&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So this seems to be working. But know we have a problem: the &lt;code&gt;*.apps&lt;/code&gt;
domain that we used for our gateway points already to the default
OpenShift Ingress. We could either&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;redeploy the gateway with a different wildcard domain (e.g. *.gtw…​)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;create a more specific DNS record that points to our new load balancer&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s try to confirm this with &lt;em&gt;curl&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ curl -I http://bla.apps.ocp.lan.stderr.at
HTTP/1.0 503 Service Unavailable
pragma: no-cache
cache-control: private, max-age=0, no-cache, no-store
content-type: text/html&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;code&gt;503&lt;/code&gt; is the response of default OpenShift Ingress.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ curl -I http://10.0.0.150
HTTP/1.1 404 Not Found
date: Fri, 29 Aug 2025 14:31:31 GMT
transfer-encoding: chunked&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Our new gateway returns a &lt;code&gt;404&lt;/code&gt; not found response. We choose the
first option and create another wildcard DNS entry for
&lt;code&gt;*.gtw.ocp.lan.stderr.at&lt;/code&gt;. We re-deployed our gateway with the new hostname:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http-gateway
namespace: openshift-ingress
spec:
gatewayClassName: openshift-default
listeners:
- name: http
protocol: HTTP
port: 80
hostname: &amp;#34;*.gtw.ocp.lan.stderr.at&amp;#34; &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;New hostname for resources exposed via our gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc apply -f gateway.yaml
gateway.gateway.networking.k8s.io/http-gateway created&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This also creates a DNSRecord resource:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc describe dnsrecords.ingress.operator.openshift.io -n openshift-ingress http-gateway-c8d7bfc67-wildcard
Name: http-gateway-c8d7bfc67-wildcard
Namespace: openshift-ingress
Labels: gateway.istio.io/managed=openshift.io-gateway-controller-v1
gateway.networking.k8s.io/gateway-name=http-gateway
istio.io/rev=openshift-gateway
Annotations: &amp;lt;none&amp;gt;
API Version: ingress.operator.openshift.io/v1
Kind: DNSRecord
Metadata:
Creation Timestamp: 2025-08-29T14:49:45Z
Finalizers:
operator.openshift.io/ingress-dns
Generation: 1
Owner References:
API Version: v1
Kind: Service
Name: http-gateway-openshift-default
UID: a023de5d-c428-4249-a190-de3cbfeb6964
Resource Version: 141150968
UID: 7a61a867-216e-40b7-88f3-e3934493c477
Spec:
Dns Management Policy: Managed
Dns Name: *.gtw.ocp.lan.stderr.at.
Record TTL: 30
Record Type: A
Targets:
10.0.0.150
Events: &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This resource is only internally used by the OpenShift ingress
operator (see &lt;code&gt;oc explain dnsrecord&lt;/code&gt; for details).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_creating_httproutes_for_exposing_our_service"&gt;Creating HTTPRoutes for exposing our service.&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To actually expose a HTTP pod via our new gateway we need:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A &lt;em&gt;Namespace&lt;/em&gt; to deploy an example pod. We will use a Nginx for this&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;em&gt;Service&lt;/em&gt; that exposes our Nginx pod&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and finally a &lt;em&gt;HTTPRoute&lt;/em&gt; resource&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;For the nginx deployment we used the following manifest:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: v1
kind: Namespace
metadata:
name: gateway-api-test
spec:
finalizers:
- kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: gateway-api-test
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: quay.io/nginx/nginx-unprivileged:1.29.1
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: gateway-api-test
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 8080
targetPort: 8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s see if our nginx pod got deployed successfully:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc get po,svc -n gateway-api-test
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-796cdf7474-b7bqz 1/1 Running 0 20s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nginx ClusterIP 172.30.42.36 &amp;lt;none&amp;gt; 8080/TCP 21s&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;And finally confirm our &lt;code&gt;Service&lt;/code&gt; is working:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc port-forward -n gateway-api-test svc/nginx 8080 &amp;amp;
Forwarding from 127.0.0.1:8080 -&amp;gt; 8080
Forwarding from [::1]:8080 -&amp;gt; 8080
$ curl -I localhost:8080
Handling connection for 8080
HTTP/1.1 200 OK
Server: nginx/1.29.1
Date: Fri, 29 Aug 2025 15:45:12 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Wed, 13 Aug 2025 14:33:41 GMT
Connection: keep-alive
ETag: &amp;#34;689ca245-267&amp;#34;
Accept-Ranges: bytes&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We received a response from our nginx pod, hurray!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So next let’s try to create a &lt;code&gt;HTTPRoute&lt;/code&gt; to expose our nginx service to external clients:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: nginx-route
spec:
parentRefs:
- name: http-gateway
namespace: openshift-ingress
hostnames: [&amp;#34;nginx.gtw.ocp.lan.stderr.at&amp;#34;]
rules:
- backendRefs:
- name: nginx
namespace: gateway-api-test
port: 8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;One important point here, the &lt;code&gt;Gateway&lt;/code&gt; actually come in two flavors&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;dedicated gateways, only accepting HTTP routes in the same namespace (&lt;code&gt;openshift-ingress&lt;/code&gt;) in our case.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;shared gateways, which also accept HTTP route objects from other namespaces&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;see &lt;a href="https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html/ingress_and_load_balancing/configuring-ingress-cluster-traffic#nw-ingress-gateway-api-deployment_ingress-gateway-api"&gt;Gateway API deployment topologies&lt;/a&gt; in the OpenShift documentation for more information.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;As this post is already rather long, we focus on the dedicated gateway topology for now.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
The HTTP route must be deployed in the same namespace as the
gateway if the dedicated topology is used.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So let’s deploy our &lt;code&gt;HTTPRoute&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc apply -f httproute.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Verify we can reach our nginx pod:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;curl -I http://nginx.gtw.ocp.lan.stderr.at
HTTP/1.1 500 Internal Server Error
date: Fri, 29 Aug 2025 15:57:34 GMT
transfer-encoding: chunked&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This return a &lt;em&gt;500&lt;/em&gt; error, something seems to be wrong with our route,
let’s take a look at the status of the &lt;code&gt;HTTPRoute&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ oc describe gtw http-gateway
.
. (output omitted)
.
Status:
Parents:
Conditions:
Last Transition Time: 2025-08-29T15:54:43Z
Message: Route was valid
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2025-08-29T15:54:43Z
Message: backendRef nginx/gateway-api-test not accessible to a HTTPRoute in namespace &amp;#34;openshift-ingress&amp;#34; (missing a ReferenceGrant?) &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
Observed Generation: 1
Reason: RefNotPermitted
Status: False &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
Type: ResolvedRefs
Controller Name: openshift.io/gateway-controller/v1
Parent Ref:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: http-gateway
Namespace: openshift-ingress&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Something seems to be wrong as the status is &lt;em&gt;False&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Seems we are missing a ReferenceGrant&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Looking at the
&lt;a href="https://gateway-api.sigs.k8s.io/api-types/referencegrant/" target="_blank" rel="noopener"&gt;upstream&lt;/a&gt;
documentation reveals a security feature of the Gateway API. Before a
&lt;code&gt;HTTPRoute&lt;/code&gt; can reach a service in a &lt;em&gt;different&lt;/em&gt; namespace we must
create a &lt;code&gt;ReferenceGrant&lt;/code&gt; in the namespace providing the service.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So let’s try to deploy following &lt;code&gt;ReferenceGrant&lt;/code&gt; in the &lt;em&gt;gateway-api-test&lt;/em&gt; namespace:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: nginx
namespace: gateway-api-test
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: openshift-ingress
to:
- group: &amp;#34;&amp;#34;
kind: Service&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Checking the status field of our &lt;code&gt;HTTPRoute&lt;/code&gt; again:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;(output omitted)
Status:
Addresses:
Type: IPAddress
Value: 10.0.0.150
Conditions:
Last Transition Time: 2025-08-29T15:47:07Z
Message: Resource accepted
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2025-08-29T15:47:08Z
Message: Resource programmed, assigned to service(s) http-gateway-openshift-default.openshift-ingress.svc.cluster.local:80
Observed Generation: 1
Reason: Programmed
Status: True &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
Type: Programmed&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Status&lt;/em&gt; is now &lt;em&gt;True&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;and finally calling the nginx pod again via our gateway:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;$ curl -I http://nginx.gtw.ocp.lan.stderr.at
HTTP/1.1 200 OK
server: nginx/1.29.1
date: Fri, 29 Aug 2025 16:01:33 GMT
content-type: text/html
content-length: 615
last-modified: Wed, 13 Aug 2025 14:33:41 GMT
etag: &amp;#34;689ca245-267&amp;#34;
accept-ranges: bytes&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Finally everything seems to be in place and working.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In this blog post we took a first look at the Kubernetes Gateway API
and it’s integration into OpenShift. We enabled the Gateway API via a
&lt;code&gt;GatewayClass&lt;/code&gt; resource, created a simple HTTP Gateway via a
&lt;code&gt;Gateway&lt;/code&gt;, deploy a Nginx pod and a Service and exposed the service
via a &lt;code&gt;HTTPRoute&lt;/code&gt; and a &lt;code&gt;ReferenceGrant&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Hopefully an upcoming blog post will cover how to&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;How to deploy a Gateway without MetalLB&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy a TLS secured service&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;implement HTTP redirects&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;rewriting URL’s (if possible)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and other possibilities of the Gateway API&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Running Falco on OpenShift 4.12</title><link>https://blog.stderr.at/openshift-platform/security/runtime-security/2023-11-26-running-falco/</link><pubDate>Sun, 26 Nov 2023 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/security/runtime-security/2023-11-26-running-falco/</guid><description>&lt;p&gt;
As mentioned in our &lt;a href="https://blog.stderr.at/openshift/2023-10-23-openshift-falco/"&gt;previous post&lt;/a&gt; about &lt;a href="https://falco.org/"&gt;Falco&lt;/a&gt;, Falco is a security
tool to monitor kernel events like system calls or Kubernetes audit
logs to provide real-time alerts.&lt;/p&gt;
&lt;p&gt;
In this post I&amp;#39;ll show to customize Falco for a specific use case.
We would like to monitor the following events:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An interactive shell is opened in a container&lt;/li&gt;
&lt;li&gt;Log all commands executed in an interactive shell in a container&lt;/li&gt;
&lt;li&gt;Log read and writes to files within an interactive shell inside a container&lt;/li&gt;
&lt;li&gt;Log commands execute via `kubectl/oc exec` which leverage the
&lt;code&gt;pod/exec&lt;/code&gt; K8s endpoint&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The rules we created for those kind of events are available &lt;a href="https://raw.githubusercontent.com/tosmi-gitops/openshift-gitops/main/components/apps/falco/overlays/custom-rules/falco-extra-rules.yaml"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div id="outline-container-headline-1" class="outline-2"&gt;
&lt;h2 id="headline-1"&gt;
Deploying custom rules and disabling the default ruleset
&lt;/h2&gt;
&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;
&lt;p&gt;
Falco comes with a quite elaborate ruleset for creating security
relevant events. But for our use case we just want to deploy a
specific set of rules (see the list above).&lt;/p&gt;
&lt;p&gt;
As we are deploying Falco via &lt;a href="https://github.com/falcosecurity/charts"&gt;Helm&lt;/a&gt;, we use the following values for
`rules_files`:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;falco&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;rules_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/etc/falco/extra-rules.d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/etc/falco/rules.d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This instructs Falco to only load rules from the directories mentioned
above.&lt;/p&gt;
&lt;p&gt;
We use a &lt;span style="text-decoration: underline;"&gt;Kustomize&lt;/span&gt; &lt;code&gt;configMapGenerator&lt;/code&gt; to create a Kubernetes &lt;code&gt;ConfigMap&lt;/code&gt;
from our custom rules file:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;configMapGenerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falco-extra-rules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;disableNameSuffixHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;falco-extra-rules.yaml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The complete &lt;span style="text-decoration: underline;"&gt;Kustomize&lt;/span&gt; configuration is &lt;a href="https://raw.githubusercontent.com/tosmi-gitops/openshift-gitops/main/components/apps/falco/overlays/custom-rules/kustomization.yaml"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
Furthermore we instruct Falco to mount our custom rule &lt;code&gt;ConfigMap&lt;/code&gt;
created above in the Helm values file:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;mounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falco-extra-rules-volume&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;configMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falco-extra-rules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumeMounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;mountPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/etc/falco/extra-rules.d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falco-extra-rules-volume&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The complete Helm values files is available &lt;a href="https://raw.githubusercontent.com/tosmi-gitops/openshift-gitops/main/components/apps/falco/base/values.yaml"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-2" class="outline-2"&gt;
&lt;h2 id="headline-2"&gt;
Disable automatic rule updates
&lt;/h2&gt;
&lt;div id="outline-text-headline-2" class="outline-text-2"&gt;
&lt;p&gt;
Falco updates all rules when it starts (via an &lt;span style="text-decoration: underline;"&gt;initContainer&lt;/span&gt;) and also
updates those rules on a regular basis. We would also like to disable
this behavior:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;falcoctl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;artifact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;install&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-3" class="outline-2"&gt;
&lt;h2 id="headline-3"&gt;
Create events for &lt;span style="text-decoration: underline;"&gt;kubectl/oc exec&lt;/span&gt;
&lt;/h2&gt;
&lt;div id="outline-text-headline-3" class="outline-text-2"&gt;
&lt;p&gt;
One problem problem is monitoring pod exec events. Using Falcos eBPF
monitoring capabilities we found no way to limit those events to pod
exec&amp;#39;s. This might be because the Falco rule language is new to us
and maybe there is a way to use eBPF filtering. Just let us know if
you find a solution!&lt;/p&gt;
&lt;p&gt;
But we came up with a different way of capturing pod/exec events:&lt;/p&gt;
&lt;p&gt;
Falco also allows monitoring Kubernetes audit events, logged by the
&lt;code&gt;kube-apiserver&lt;/code&gt;. Every time you hit the &lt;code&gt;pod/exec&lt;/code&gt; endpoint, K8s logs the
following event in the audit log:&lt;/p&gt;
&lt;div class="src src-json"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;apiVersion&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;audit.k8s.io/v1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;level&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Metadata&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;auditID&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;5c19c1d0-00a7-4af5-a236-5345b5963581&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;stage&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ResponseComplete&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;requestURI&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/api/v1/namespaces/falco/pods/falco-8mqj7/exec?command=cat\u0026command=%2Fetc%2Ffalco%2Fextra-rules.d%2Ffalco-extra-rules.yaml\u0026container=falco\u0026stderr=true\u0026stdout=true&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;verb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;create&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;uid&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;d82ec74a-75e3-4798-a084-4b766dcea5ef&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;groups&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cluster-admins&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;system:authenticated:oauth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;system:authenticated&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;extra&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;scopes.authorization.openshift.io&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;user:full&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]}},&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;sourceIPs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.0.32.220&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;userAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;oc/4.13.0 (linux/amd64) kubernetes/92b1a3d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;objectRef&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;resource&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pods&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;namespace&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;falco&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;falco-8mqj7&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;apiVersion&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;subresource&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;exec&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;responseStatus&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;metadata&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:{},&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;requestReceivedTimestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;2023-11-13T17:23:16.999602Z&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;stageTimestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;2023-11-13T17:23:17.231121Z&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;annotations&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;authorization.k8s.io/decision&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;allow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;authorization.k8s.io/reason&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;RBAC: allowed by ClusterRoleBinding \&amp;#34;root-cluster-admin\&amp;#34; of ClusterRole \&amp;#34;cluster-admin\&amp;#34; to User \&amp;#34;root\&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
As you can hopefully see, the command executed is available in the
&lt;span style="text-decoration: underline;"&gt;requestURI&lt;/span&gt; field.&lt;/p&gt;
&lt;p&gt;
So we enabled the &lt;span style="text-decoration: underline;"&gt;k8saudit&lt;/span&gt; Falco plugin and created an additional rule
for those kind of events.&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;falco&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;k8saudit&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;library_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;libk8saudit.so&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;init_config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# maxEventSize: 262144&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# webhookMaxBatchSize: 12582912&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# sslCertificate: /etc/falco/falco.pem&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# open_params: &amp;#34;http://:9765/k8s-audit&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;open_params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/host/var/log/kube-apiserver/audit.log&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;library_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;libjson.so&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;init_config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-4" class="outline-2"&gt;
&lt;h2 id="headline-4"&gt;
Implementing event routing
&lt;/h2&gt;
&lt;div id="outline-text-headline-4" class="outline-text-2"&gt;
&lt;p&gt;
We had an additional requirement to route events based on the following rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Events that &lt;strong&gt;do not&lt;/strong&gt; contain sensitive data (like usernames) should go
to a specific Kafka topic&lt;/li&gt;
&lt;li&gt;Events that &lt;strong&gt;do&lt;/strong&gt; contain sensitive data (like usernames) should be
routed to another Kafka topic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our first thought was to leverage Falcosidekick&amp;#39;s &lt;a href="https://github.com/falcosecurity/falcosidekick/blob/2.28.0/config_example.yaml#L279"&gt;minimumpriority&lt;/a&gt;
field for routing. Events with sensitive data would get a higher
priority. But the sink with a lower &lt;span style="text-decoration: underline;"&gt;minimumpriority&lt;/span&gt; would get events
with higher priority as well, which means events with sensitive data.&lt;/p&gt;
&lt;p&gt;
Furthermore as far as we know Falco currently only supports one Kafka
configuration (we need two for two topics).&lt;/p&gt;
&lt;p&gt;
At this point in time we are not aware of a possibility to implement
this with Falco or Falcosidekick directly.&lt;/p&gt;
&lt;p&gt;
There are some discussions upstream on implementing such a feature:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/falcosecurity/falcosidekick/issues/161"&gt;https://github.com/falcosecurity/falcosidekick/issues/161&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/falcosecurity/falcosidekick/issues/161#issuecomment-747714289"&gt;https://github.com/falcosecurity/falcosidekick/issues/161#issuecomment-747714289&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/falcosecurity/falcosidekick/issues/224"&gt;https://github.com/falcosecurity/falcosidekick/issues/224&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our current idea is to use &lt;a href="https://vector.dev/"&gt;Vector&lt;/a&gt; for event routing. We will try to
implement the following pipeline:&lt;/p&gt;
&lt;p&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/security/runtime-security/images/falco/falco-pipeline.png" alt="/openshift-platform/security/runtime-security/images/falco/falco-pipeline.png" title="/openshift-platform/security/runtime-security/images/falco/falco-pipeline.png" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-5" class="outline-2"&gt;
&lt;h2 id="headline-5"&gt;
Tips and Tricks
&lt;/h2&gt;
&lt;div id="outline-text-headline-5" class="outline-text-2"&gt;
&lt;div id="outline-container-headline-6" class="outline-3"&gt;
&lt;h3 id="headline-6"&gt;
Monitor Redis disk usage
&lt;/h3&gt;
&lt;div id="outline-text-headline-6" class="outline-text-3"&gt;
&lt;p&gt;
One small hint when using &lt;code&gt;falcosidekick-ui&lt;/code&gt; to debug/monitor events. It
happened to us that the Redis volume was full and suddenly we couldn&amp;#39;t
see new events in the UI.&lt;/p&gt;
&lt;p&gt;
We stopped the UI and Redis pods, removed the PVC and just ran our kustomization
again, to recreate the PVC and the pods.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-7" class="outline-3"&gt;
&lt;h3 id="headline-7"&gt;
Monitor &lt;span style="text-decoration: underline;"&gt;falco&lt;/span&gt; pod logs when changing rules
&lt;/h3&gt;
&lt;div id="outline-text-headline-7" class="outline-text-3"&gt;
&lt;p&gt;
It&amp;#39;s always wise to monitor one Falco pod for errors when deploying
new rules, for example at one point we hit the following error:&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&amp;#34;hostname&amp;#34;:&amp;#34;falco-2hlkm&amp;#34;,&amp;#34;output&amp;#34;:&amp;#34;Falco internal: hot restart failure: /etc/falco/extra-rules.d/falco-extra-rules.yaml: Invalid\n1 Errors:\nIn rules content: (/etc/falco/extra-rules.d/falco-extra-rules.yaml:0:0)\n rule &amp;#39;Terminal shell in container&amp;#39;: (/etc/falco/extra-rules.d/falco-extra-rules.yaml:25:2)\n condition expression: (\&amp;#34;spawned_process a...\&amp;#34;:26:71)\n------\n...ocess and container and shell_procs and proc.tty != 0 and container_entrypoint\n ^\n------\nLOAD_ERR_VALIDATE (Error validating rule/macro/list/exception objects): Undefined macro &amp;#39;container_entrypoint&amp;#39; used in filter.\n&amp;#34;,&amp;#34;output_fields&amp;#34;:{},&amp;#34;priority&amp;#34;:&amp;#34;Critical&amp;#34;,&amp;#34;rule&amp;#34;:&amp;#34;Falco internal: hot restart failure&amp;#34;,&amp;#34;source&amp;#34;:&amp;#34;internal&amp;#34;,&amp;#34;time&amp;#34;:&amp;#34;2023-11-13T11:47:14.639547735Z&amp;#34;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Falco is quite resilient when it comes to errors in rules files and
provides useful hints on what might be wrong:&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Undefined macro &amp;#39;container_entrypoint&amp;#39; used in filter&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
So we just added the missing macro and all was swell again.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Setting up Falco on OpenShift 4.12</title><link>https://blog.stderr.at/openshift-platform/security/runtime-security/2023-10-23-openshift-falco/</link><pubDate>Mon, 23 Oct 2023 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/security/runtime-security/2023-10-23-openshift-falco/</guid><description>&lt;p&gt;
&lt;a href="https://falco.org/"&gt;Falco&lt;/a&gt; is a security tool to monitor kernel events like system calls to
provide real-time alerts. In this post I&amp;#39;ll document the steps taken
to get Open Source &lt;a href="https://falco.org/"&gt;Falco&lt;/a&gt; running on an OpenShift 4.12 cluster.&lt;/p&gt;
&lt;p&gt;
&lt;a href="https://blog.stderr.at/openshift/2023-10-23-openshift-falco/#headline-4"&gt;UPDATE&lt;/a&gt;: Use the &lt;code&gt;falco-driver-loader-legacy&lt;/code&gt; image for OpenShift 4.12 deployments.&lt;/p&gt;
&lt;div id="outline-container-headline-1" class="outline-2"&gt;
&lt;h2 id="headline-1"&gt;
First Try
&lt;/h2&gt;
&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;
&lt;p&gt;
We will use the &lt;a href="https://falcosecurity.github.io/charts"&gt;Falco Helm chart&lt;/a&gt; version 3.8.0 for our first try of setting up Falco on our OpenShift cluster.&lt;/p&gt;
&lt;p&gt;
This is our values file:&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;driver:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; kind: ebpf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; json_output: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; json_include_output_property: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; log_syslog: false
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; log_level: info
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falcosidekick:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; enabled: true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; webui:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; enabled: true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We would like to use the eBPF driver to monitor kernel events, enable
falco sidekick, which is used to route events and the falco sidekick
UI for easier testing.&lt;/p&gt;
&lt;p&gt;
Because of reasons we leverage kustomize to render the helm chart. The
final kustomize config is &lt;a href="https://github.com/tosmi-gitops/openshift-gitops/tree/main/components/apps/falco/base"&gt;here&lt;/a&gt; (after fixing all problems mentioned
below).&lt;/p&gt;
&lt;p&gt;
So after deploying the chart via ArgoCD (another story), we have the following pods:&lt;/p&gt;
&lt;div class="src src-bash"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get pods -n falco
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-4cc8j 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;95s ago&lt;span class="o"&gt;)&lt;/span&gt; 4m31s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-bx87j 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;75s ago&lt;span class="o"&gt;)&lt;/span&gt; 4m29s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-ds9w6 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;99s ago&lt;span class="o"&gt;)&lt;/span&gt; 4m30s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-falcosidekick-ui-redis-0 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 4m28s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-gxznz 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;14s ago&lt;span class="o"&gt;)&lt;/span&gt; 4m30s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-vtnk5 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;98s ago&lt;span class="o"&gt;)&lt;/span&gt; 4m29s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-wbn2k 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;80s ago&lt;span class="o"&gt;)&lt;/span&gt; 4m29s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
hm, not so good. Seems like some &lt;code&gt;initContainers&lt;/code&gt; are failing.&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s check the &lt;code&gt;falco-driver-loader&lt;/code&gt; initContainer:&lt;/p&gt;
&lt;div class="src src-bash"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Setting up /usr/src links from host
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Running falco-driver-loader &lt;span class="k"&gt;for&lt;/span&gt;: falco &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.36.1, driver &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6.0.1+driver, &lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;x86_64, kernel &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4.18.0-372.73.1.el8_6.x86_64, kernel &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Running falco-driver-loader with: &lt;span class="nv"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bpf, &lt;span class="nv"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes, &lt;span class="nv"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Mounting debugfs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount: /sys/kernel/debug: permission denied.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dmesg&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; may have more information after failed mount system call.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Filename &lt;span class="s1"&gt;&amp;#39;falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o&amp;#39;&lt;/span&gt; is composed of:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - driver name: falco
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - target identifier: rhcos
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - kernel release: 4.18.0-372.73.1.el8_6.x86_64
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - kernel version: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Trying to download a prebuilt eBPF probe from https://download.falco.org/driver/6.0.1%2Bdriver/x86_64/falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl: &lt;span class="o"&gt;(&lt;/span&gt;22&lt;span class="o"&gt;)&lt;/span&gt; The requested URL returned error: &lt;span class="m"&gt;404&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Unable to find a prebuilt falco eBPF probe
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Trying to compile the eBPF probe &lt;span class="o"&gt;(&lt;/span&gt;falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;expr: syntax error: unexpected argument &lt;span class="s1"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make&lt;span class="o"&gt;[&lt;/span&gt;1&lt;span class="o"&gt;]&lt;/span&gt;: *** /lib/modules/4.18.0-372.73.1.el8_6.x86_64/build: No such file or directory. Stop.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make: *** &lt;span class="o"&gt;[&lt;/span&gt;Makefile:38: all&lt;span class="o"&gt;]&lt;/span&gt; Error &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mv: cannot stat &lt;span class="s1"&gt;&amp;#39;/usr/src/falco-6.0.1+driver/bpf/probe.o&amp;#39;&lt;/span&gt;: No such file or directory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Unable to load the falco eBPF probe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Seems to be an issue with a missing directory &lt;span style="text-decoration: underline;"&gt;/lib/modules/4.18.0-372.73.1.el8_6.x86_64/build&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;
And we told the helm chart to enable &lt;code&gt;falco-sidekick&lt;/code&gt; and
&lt;code&gt;falco-sidekick-ui&lt;/code&gt;, but where are they?&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s check the events with &lt;code&gt;oc get events&lt;/code&gt; as well, and what do we see?&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;8s Warning FailedCreate replicaset/falco-falcosidekick-7cfbbbf89f Error creating: pods &lt;span class="s2"&gt;&amp;#34;falco-falcosidekick-7cfbbbf89f-&amp;#34;&lt;/span&gt; is forbidden: unable to validate against any security context constraint: &lt;span class="o"&gt;[&lt;/span&gt;provider &lt;span class="s2"&gt;&amp;#34;anyuid&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider restricted-v2: .spec.securityContext.fsGroup: Invalid value: &lt;span class="o"&gt;[]&lt;/span&gt;int64&lt;span class="o"&gt;{&lt;/span&gt;1234&lt;span class="o"&gt;}&lt;/span&gt;: &lt;span class="m"&gt;1234&lt;/span&gt; is not an allowed group, provider restricted-v2: .containers&lt;span class="o"&gt;[&lt;/span&gt;0&lt;span class="o"&gt;]&lt;/span&gt;.runAsUser: Invalid value: 1234: must be in the ranges: &lt;span class="o"&gt;[&lt;/span&gt;1000730000, 1000739999&lt;span class="o"&gt;]&lt;/span&gt;, provider &lt;span class="s2"&gt;&amp;#34;restricted&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;nonroot-v2&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;nonroot&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;hostmount-anyuid&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;machine-api-termination-handler&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;hostnetwork-v2&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;hostnetwork&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;hostaccess&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;falco&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;node-exporter&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;privileged&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6s Warning FailedCreate replicaset/falco-falcosidekick-ui-76885bd484 Error creating: pods &lt;span class="s2"&gt;&amp;#34;falco-falcosidekick-ui-76885bd484-&amp;#34;&lt;/span&gt; is forbidden: unable to validate against any security context constraint: &lt;span class="o"&gt;[&lt;/span&gt;provider &lt;span class="s2"&gt;&amp;#34;anyuid&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider restricted-v2: .spec.securityContext.fsGroup: Invalid value: &lt;span class="o"&gt;[]&lt;/span&gt;int64&lt;span class="o"&gt;{&lt;/span&gt;1234&lt;span class="o"&gt;}&lt;/span&gt;: &lt;span class="m"&gt;1234&lt;/span&gt; is not an allowed group, provider restricted-v2: .containers&lt;span class="o"&gt;[&lt;/span&gt;0&lt;span class="o"&gt;]&lt;/span&gt;.runAsUser: Invalid value: 1234: must be in the ranges: &lt;span class="o"&gt;[&lt;/span&gt;1000730000, 1000739999&lt;span class="o"&gt;]&lt;/span&gt;, provider &lt;span class="s2"&gt;&amp;#34;restricted&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;nonroot-v2&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;nonroot&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;hostmount-anyuid&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;machine-api-termination-handler&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;hostnetwork-v2&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;hostnetwork&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;hostaccess&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;falco&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;node-exporter&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount, provider &lt;span class="s2"&gt;&amp;#34;privileged&amp;#34;&lt;/span&gt;: Forbidden: not usable by user or serviceaccount&lt;span class="o"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Looks like a problem with OpenShifts Security Context constraints (SCC&amp;#39;s).&lt;/p&gt;
&lt;div id="outline-container-headline-2" class="outline-3"&gt;
&lt;h3 id="headline-2"&gt;
Summary of problems
&lt;/h3&gt;
&lt;div id="outline-text-headline-2" class="outline-text-3"&gt;
&lt;ul&gt;
&lt;li&gt;The falco &lt;code&gt;DaemonSet&lt;/code&gt; fails to start pods because there is an issue with a missing directory&lt;/li&gt;
&lt;li&gt;Falco Sidekick and Falco Sidekick UI fails to start because of
Security Context Constraint (SCC) issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-3" class="outline-2"&gt;
&lt;h2 id="headline-3"&gt;
Fixing the Falco daemonset
&lt;/h2&gt;
&lt;div id="outline-text-headline-3" class="outline-text-2"&gt;
&lt;p&gt;
Falco tries to download a pre-compiled eBPF probe, fails and then
tries to compile that probe for our host OS kernel. This fails with the message:&lt;/p&gt;
&lt;div class="src src-bash"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make&lt;span class="o"&gt;[&lt;/span&gt;1&lt;span class="o"&gt;]&lt;/span&gt;: *** /lib/modules/4.18.0-372.73.1.el8_6.x86_64/build: No such file or directory. Stop.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
As far as we know there are no kernel sources installed on RHCOS nodes
in OpenShift. After a little bit of searching the interweb we found
the following issue comment on Github:&lt;/p&gt;
&lt;p&gt;
&lt;a href="https://github.com/falcosecurity/falco/issues/1505#issuecomment-754745960"&gt;OpenShift under vsphere: Download failed, consider compiling your own falco module and loading it or getting in touch with the Falco community&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
So we need to enable the &lt;code&gt;kernel-devel&lt;/code&gt; extension, the official docs are
&lt;a href="https://docs.openshift.com/container-platform/4.12/post_installation_configuration/machine-configuration-tasks.html#rhcos-add-extensions_post-install-machine-configuration-tasks"&gt;here&lt;/a&gt;. It does not mention &lt;code&gt;kernel-devel&lt;/code&gt;, but there&amp;#39;s a &lt;a href="https://access.redhat.com/solutions/6972423"&gt;knowledge base
article&lt;/a&gt; mentioning &lt;code&gt;kernel-devel&lt;/code&gt;, so let&amp;#39;s give it a try.&lt;/p&gt;
&lt;p&gt;
We deploy two &lt;code&gt;MachineConfigs&lt;/code&gt;, one for &lt;a href="https://github.com/tosmi-gitops/openshift-gitops/blob/main/components/apps/falco/base/worker-machineconfig.yaml"&gt;worker&lt;/a&gt; and one for &lt;a href="https://github.com/tosmi-gitops/openshift-gitops/blob/main/components/apps/falco/base/master-machineconfig.yaml"&gt;master&lt;/a&gt; nodes
to rollout the extension, the worker configuration looks like this:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;machineconfiguration.openshift.io/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;MachineConfig&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;machineconfiguration.openshift.io/role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;worker&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;99&lt;/span&gt;-&lt;span class="l"&gt;worker-kernel-devel-extensions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;kernel-devel&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
See also our Kustomize configuration &lt;a href="https://github.com/tosmi-gitops/openshift-gitops/blob/main/components/apps/falco/base/kustomization.yaml"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
As soon as we apply our &lt;code&gt;MachineConfigs&lt;/code&gt;, OpenShift starts the rollout via MaschineConfigPool&amp;#39;s:&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get mcp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME CONFIG UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT UPDATEDMACHINECOUNT DEGRADEDMACHINECOUNT AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;master rendered-master-ce464ff45cc049fce3e8a63e36a4ee9e False True False 3 0 0 0 13d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;worker rendered-worker-a0f8f0d915ef01ba4a1ab3047b6c863d False True False 3 0 0 0 13d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
When the rollout is done, let&amp;#39;s restart all Falco &lt;code&gt;DaemonSet&lt;/code&gt; pods:&lt;/p&gt;
&lt;div class="src src-bash"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc delete pods -l app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;falco&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
And check the status:&lt;/p&gt;
&lt;div class="src src-bash"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-5wfnk 0/2 Init:Error &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;3s ago&lt;span class="o"&gt;)&lt;/span&gt; 7s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-66fxw 0/2 Init:0/2 &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;2s ago&lt;span class="o"&gt;)&lt;/span&gt; 6s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-6fbc7 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;2s ago&lt;span class="o"&gt;)&lt;/span&gt; 8s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-8h8n4 0/2 Init:0/2 &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;2s ago&lt;span class="o"&gt;)&lt;/span&gt; 6s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-falcosidekick-ui-redis-0 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 18m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-nhld2 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;2s ago&lt;span class="o"&gt;)&lt;/span&gt; 6s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-xqv4b 0/2 Init:CrashLoopBackOff &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;3s ago&lt;span class="o"&gt;)&lt;/span&gt; 8s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
still, the &lt;code&gt;initContainers&lt;/code&gt; fail. Lets check the log again&lt;/p&gt;
&lt;div class="src src-bash"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc logs -c falco-driver-loader falco-5wfnk
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Setting up /usr/src links from host
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Running falco-driver-loader &lt;span class="k"&gt;for&lt;/span&gt;: falco &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.36.1, driver &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6.0.1+driver, &lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;x86_64, kernel &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4.18.0-372.73.1.el8_6.x86_64, kernel &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Running falco-driver-loader with: &lt;span class="nv"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bpf, &lt;span class="nv"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes, &lt;span class="nv"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Mounting debugfs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount: /sys/kernel/debug: permission denied.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dmesg&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; may have more information after failed mount system call.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Filename &lt;span class="s1"&gt;&amp;#39;falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o&amp;#39;&lt;/span&gt; is composed of:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - driver name: falco
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - target identifier: rhcos
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - kernel release: 4.18.0-372.73.1.el8_6.x86_64
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - kernel version: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Trying to download a prebuilt eBPF probe from https://download.falco.org/driver/6.0.1%2Bdriver/x86_64/falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl: &lt;span class="o"&gt;(&lt;/span&gt;22&lt;span class="o"&gt;)&lt;/span&gt; The requested URL returned error: &lt;span class="m"&gt;404&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Unable to find a prebuilt falco eBPF probe
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Trying to compile the eBPF probe &lt;span class="o"&gt;(&lt;/span&gt;falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Makefile:1005: *** &lt;span class="s2"&gt;&amp;#34;Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel&amp;#34;&lt;/span&gt;. Stop.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make: *** &lt;span class="o"&gt;[&lt;/span&gt;Makefile:38: all&lt;span class="o"&gt;]&lt;/span&gt; Error &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mv: cannot stat &lt;span class="s1"&gt;&amp;#39;/usr/src/falco-6.0.1+driver/bpf/probe.o&amp;#39;&lt;/span&gt;: No such file or directory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Unable to load the falco eBPF probe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
So this time we get another error, the culprit is the following line&lt;/p&gt;
&lt;div class="src src-bash"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Makefile:1005: *** &lt;span class="s2"&gt;&amp;#34;Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel&amp;#34;&lt;/span&gt;. Stop.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Back to searching the interweb only reveals an old &lt;a href="https://github.com/falcosecurity/falco/issues/376"&gt;issue&lt;/a&gt;, that should
be fixed already.&lt;/p&gt;
&lt;p&gt;
So as a quick hack we &lt;a href="https://github.com/tosmi/playground/blob/master/openshift/falco/custom-falco-driver-loader/Dockerfile"&gt;modified&lt;/a&gt; the &lt;code&gt;falco-driver-loader&lt;/code&gt; image to
contain &lt;code&gt;libelf-dev&lt;/code&gt; and pushed to image to &lt;a href="https://quay.io/repository/tosmi/falco-driver-loader?tab=tags"&gt;quay&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
We then modified our falco helm configuration to use the updated image:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ebpf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;initContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;quay.io&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;tosmi/falco-driver-loader&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0.36.1&lt;/span&gt;-&lt;span class="l"&gt;libelf-dev&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;falco&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;json_output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;json_include_output_property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;log_syslog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;log_level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;info&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;falcosidekick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;webui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Note the updated &lt;code&gt;diver.loader.initContainer&lt;/code&gt; section.&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s check the our pods again:&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-2ssgx 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 66s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-5hqgg 1/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 66s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-82kq9 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 65s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-99zxw 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 65s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-falcosidekick-test-connection 0/1 Error &lt;span class="m"&gt;0&lt;/span&gt; 67s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-falcosidekick-ui-redis-0 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 31m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-slx5k 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 65s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-tzm8d 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 65s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Success! This time the &lt;code&gt;DaemonSet&lt;/code&gt; pods started successfully. Just note
that you have to be patient. The first start took about 1-2 minutes to
complete.&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s check the logs of one &lt;code&gt;DaemonSet&lt;/code&gt; pod just to sure:&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;oc logs -c falco-driver-loader falco-2ssgx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Setting up /usr/src links from host
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Running falco-driver-loader &lt;span class="k"&gt;for&lt;/span&gt;: falco &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.36.1, driver &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6.0.1+driver, &lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;x86_64, kernel &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4.18.0-372.73.1.el8_6.x86_64, kernel &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Running falco-driver-loader with: &lt;span class="nv"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bpf, &lt;span class="nv"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes, &lt;span class="nv"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Mounting debugfs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount: /sys/kernel/debug: permission denied.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; dmesg&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; may have more information after failed mount system call.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Filename &lt;span class="s1"&gt;&amp;#39;falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o&amp;#39;&lt;/span&gt; is composed of:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - driver name: falco
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - target identifier: rhcos
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - kernel release: 4.18.0-372.73.1.el8_6.x86_64
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - kernel version: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Trying to download a prebuilt eBPF probe from https://download.falco.org/driver/6.0.1%2Bdriver/x86_64/falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl: &lt;span class="o"&gt;(&lt;/span&gt;22&lt;span class="o"&gt;)&lt;/span&gt; The requested URL returned error: &lt;span class="m"&gt;404&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Unable to find a prebuilt falco eBPF probe
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Trying to compile the eBPF probe &lt;span class="o"&gt;(&lt;/span&gt;falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* eBPF probe located in /root/.falco/6.0.1+driver/x86_64/falco_rhcos_4.18.0-372.73.1.el8_6.x86_64_1.o
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Success: eBPF probe symlinked to /root/.falco/falco-bpf.o&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Especially the line&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Success: eBPF probe symlinked to /root/.falco/falco-bpf.o&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
looks promising. So up to the next problem, getting falco-sidekick and falco-sidekick-ui running.&lt;/p&gt;
&lt;p&gt;
We also &lt;a href="https://github.com/falcosecurity/falco/issues/2884"&gt;opened a bug&lt;/a&gt; report upstream to get feedback from the
developers on this issue.&lt;/p&gt;
&lt;div id="outline-container-headline-4" class="outline-3"&gt;
&lt;h3 id="headline-4"&gt;
UPDATE
&lt;/h3&gt;
&lt;div id="outline-text-headline-4" class="outline-text-3"&gt;
&lt;p&gt;
&lt;a href="https://github.com/Andreagit97"&gt;Andreagit97&lt;/a&gt; was so nice mentioning in the issue above that
actually there is an image with libelf-dev available,
&lt;a href="https://hub.docker.com/r/falcosecurity/falco-driver-loader-legacy"&gt;falco-driver-loader-legacy&lt;/a&gt;. We can confirm that this image fixes the
problem mentioned above.&lt;/p&gt;
&lt;p&gt;
So this is our final falco helm chart values.yaml:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ebpf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;initContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falcosecurity/falco-driver-loader-legacy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;falco&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;json_output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;json_include_output_property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;log_syslog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;log_level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;info&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;falcosidekick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;webui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-5" class="outline-2"&gt;
&lt;h2 id="headline-5"&gt;
Fixing falco-sidekick and falco-sidekick-ui
&lt;/h2&gt;
&lt;div id="outline-text-headline-5" class="outline-text-2"&gt;
&lt;p&gt;
Remember pod startup actually failed because of the following event (check with &lt;code&gt;oc get events&lt;/code&gt;):&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;.spec.securityContext.fsGroup: Invalid value: []int64{1234}: 1234 is not an allowed group&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
It seems the sidekick pods want to run with a specific UID. The
default OpenShift Security Context Constraint (SCC) &lt;code&gt;restricted&lt;/code&gt;
prohibits this.&lt;/p&gt;
&lt;p&gt;
Lets confirm our suspicion:&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get deploy -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.spec.template.spec.securityContext}{&amp;#34;\n&amp;#34;}&amp;#39;&lt;/span&gt; falco-falcosidekick
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;fsGroup&amp;#34;&lt;/span&gt;:1234,&lt;span class="s2"&gt;&amp;#34;runAsUser&amp;#34;&lt;/span&gt;:1234&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get deploy -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.spec.template.spec.securityContext}{&amp;#34;\n&amp;#34;}&amp;#39;&lt;/span&gt; falco-falcosidekick-ui
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;fsGroup&amp;#34;&lt;/span&gt;:1234,&lt;span class="s2"&gt;&amp;#34;runAsUser&amp;#34;&lt;/span&gt;:1234&lt;span class="o"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Bingo! &lt;code&gt;securityContext&lt;/code&gt; is set to 1234 for both deployments. There is
another SCC that we could leverage, &lt;code&gt;nonroot&lt;/code&gt;, which basically allows any
UID expect 0. We just need to get the &lt;code&gt;ServiceAccount&lt;/code&gt; that
falco-sidekick and falco-sidekick-ui are actually using:&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get deploy -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.spec.template.spec.serviceAccount}{&amp;#34;\n&amp;#34;}&amp;#39;&lt;/span&gt; falco-falcosidekick
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-falcosidekick
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get deploy -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.spec.template.spec.serviceAccount}{&amp;#34;\n&amp;#34;}&amp;#39;&lt;/span&gt; falco-falcosidekick-ui
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;falco-falcosidekick-ui&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
So falco-sidekick uses &lt;code&gt;falco-sidekick&lt;/code&gt; as &lt;code&gt;ServiceAccount&lt;/code&gt; and falco-sidekick-ui &lt;code&gt;falco-sidekick-ui&lt;/code&gt;. Lets
grant both &lt;code&gt;ServiceAccounts&lt;/code&gt; access to the &lt;code&gt;nonroot&lt;/code&gt; SCC.&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kind: ClusterRoleBinding
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: falco-falcosidekick-scc:nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;roleRef:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; apiGroup: rbac.authorization.k8s.io
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; kind: ClusterRole
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: system:openshift:scc:nonroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;subjects:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- kind: ServiceAccount
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: falco-falcosidekick
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: falco
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- kind: ServiceAccount
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: falco-falcosidekick-ui
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; namespace: falco&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We&amp;#39;ve already added this &lt;a href="https://github.com/tosmi-gitops/openshift-gitops/blob/main/components/apps/falco/base/falcosidekick-any-uid-scc.yaml"&gt;file&lt;/a&gt; to our &lt;a href="https://github.com/tosmi-gitops/openshift-gitops/blob/main/components/apps/falco/base/falcosidekick-any-uid-scc.yaml#L19"&gt;Kustomize&lt;/a&gt; configuration.&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s trigger a redeployment by deleting the &lt;code&gt;ReplicaSets&lt;/code&gt; of both deployments, they will be re-created automatically:&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc delete rs -l app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;falcosidekick
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc delete rs -l app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;falcosidekick-ui&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Finally let&amp;#39;s confirm everything is up and running:&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get deploy,ds,pods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY UP-TO-DATE AVAILABLE AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;deployment.apps/falco-falcosidekick 2/2 &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; 5d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;deployment.apps/falco-falcosidekick-ui 2/2 &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; 5d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;daemonset.apps/falco &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &amp;lt;none&amp;gt; 6d2h
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-2ssgx 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 21m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-5hqgg 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 21m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-82kq9 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 21m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-99zxw 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 21m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-falcosidekick-7cfbbbf89f-qxwxs 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 118s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-falcosidekick-7cfbbbf89f-rz5lj 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 118s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-falcosidekick-ui-76885bd484-p7lqm 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 2m18s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-falcosidekick-ui-76885bd484-sfgh4 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 2m18s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-falcosidekick-ui-redis-0 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 51m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-slx5k 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 21m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/falco-tzm8d 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 21m&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-6" class="outline-2"&gt;
&lt;h2 id="headline-6"&gt;
Testing Falco
&lt;/h2&gt;
&lt;div id="outline-text-headline-6" class="outline-text-2"&gt;
&lt;p&gt;
Now that everything seems to be running, lets do a quick test. First
we will try to access the Falco Sidekick user interface.&lt;/p&gt;
&lt;p&gt;
Falco will not deploy a route for the UI automatically, instead we&amp;#39;ve
created a &lt;a href="https://github.com/tosmi-gitops/openshift-gitops/tree/main/components/apps/falco/overlays/sidekick-ui-route"&gt;Kustomize overlay&lt;/a&gt; with a custom route:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;route.openshift.io/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Route&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falco-falcosidekick-ui&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falco&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falcosidekick-ui.apps.hub.aws.tntinfra.net&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;targetPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;http&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;termination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;edge&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Service&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;falco-falcosidekick-ui&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;wildcardPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;None&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
After deploying the &lt;code&gt;Route&lt;/code&gt; we can access the Falco UI with the hostname
specified in the route object. The default username seems to be
&lt;span style="text-decoration: underline;"&gt;admin/admin&lt;/span&gt; which is kind of strange for a security tool, maybe that&amp;#39;s
the reason Falco does not expose the UI per default.&lt;/p&gt;
&lt;p&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/security/runtime-security/images/falco/falco-ui.png" alt="/openshift-platform/security/runtime-security/images/falco/falco-ui.png" title="/openshift-platform/security/runtime-security/images/falco/falco-ui.png" /&gt;&lt;/p&gt;
&lt;div id="outline-container-headline-7" class="outline-3"&gt;
&lt;h3 id="headline-7"&gt;
Creating an event
&lt;/h3&gt;
&lt;div id="outline-text-headline-7" class="outline-text-3"&gt;
&lt;p&gt;
As a last test let&amp;#39;s try to trigger an event. We open a shell to one
of the falco &lt;code&gt;DaemonSet&lt;/code&gt; pods and execute a suspicious command:&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc rsh falco-2ssgx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Defaulted container &lt;span class="s2"&gt;&amp;#34;falco&amp;#34;&lt;/span&gt; out of: falco, falcoctl-artifact-follow, falco-driver-loader &lt;span class="o"&gt;(&lt;/span&gt;init&lt;span class="o"&gt;)&lt;/span&gt;, falcoctl-artif# cat /etc/shadow
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;root:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;daemon:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bin:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sys:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sync:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;games:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;man:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lp:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mail:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;news:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uucp:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;proxy:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;www-data:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backup:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;list:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;irc:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;_apt:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nobody:*:19639:0:99999:7:::
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
and we can see an event with priority &lt;strong&gt;Warning&lt;/strong&gt; in the Falco ui.&lt;/p&gt;
&lt;p&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/security/runtime-security/images/falco/falco-cat-etc-shadow.png" alt="/openshift-platform/security/runtime-security/images/falco/falco-cat-etc-shadow.png" title="/openshift-platform/security/runtime-security/images/falco/falco-cat-etc-shadow.png" /&gt;&lt;/p&gt;
&lt;p&gt;
That&amp;#39;s it, seems like Falco is successfully running on OpenShift 4.12.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>How to force a MachineConfig rollout</title><link>https://blog.stderr.at/openshift-platform/day-2/fundamentals/2023-10-18-force-machineconfig-rollout/</link><pubDate>Wed, 18 Oct 2023 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/day-2/fundamentals/2023-10-18-force-machineconfig-rollout/</guid><description>&lt;p&gt;
While playing around with &lt;a href="https://falco.org/"&gt;Falco&lt;/a&gt; (worth another post) I had to force a
MachineConfig update even so the actual configuration of the machine
did not change.&lt;/p&gt;
&lt;p&gt;
This posts documents the steps taken.&lt;/p&gt;
&lt;p&gt;
As this seems to be not clearly documented here it comes&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Get the list of current MachineConfigs&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get mc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME GENERATEDBYCONTROLLER IGNITIONVERSION AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;00-master 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;00-worker 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;01-master-container-runtime 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;01-master-kubelet 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;01-worker-container-runtime 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;01-worker-kubelet 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;99-kernel-devel-extensions 25h
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;99-master-generated-registries 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;99-master-ssh 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;99-worker-generated-registries 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;99-worker-ssh 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rendered-master-b8a2011b0b09e36088acf47e225b0ed2 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 5h49m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rendered-master-ce464ff45cc049fce3e8a63e36a4ee9e 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rendered-worker-5baefb5bb7ad1d69cd7a0c3dc52ef2f3 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 25h
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rendered-worker-a0f8f0d915ef01ba4a1ab3047b6c863d 7101fb0720d05771bdc174af918b64deb4efa604 3.2.0 8d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We want to force the rollout of a worker node, so remember the name of an old worker config, in our case &lt;code&gt;rendered-worker-5baefb5bb7ad1d69cd7a0c3dc52ef2f3&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Currently the desiredConfig and the currentConfig should have the same value&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$oc&lt;/span&gt; get node node1 -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.metadata.annotations.machineconfiguration\.openshift\.io/desiredConfig}{&amp;#34;\n&amp;#34;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rendered-worker-a0f8f0d915ef01ba4a1ab3047b6c863d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get node node1 -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.metadata.annotations.machineconfiguration\.openshift\.io/currentConfig}{&amp;#34;\n&amp;#34;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rendered-worker-a0f8f0d915ef01ba4a1ab3047b6c863d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Touch a file called 4 touch /run/machine-config-daemon-force&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;oc debug node/node1 -- touch /host/run/machine-config-daemon-force&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;patch the node and set the annotation &lt;code&gt;machineconfiguration.openshift.io/currentConfig&lt;/code&gt; to the &lt;strong&gt;old&lt;/strong&gt; rendered config rendered-worker-5baefb5bb7ad1d69cd7a0c3dc52ef2f3&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;oc patch node ip-10-0-182-18.eu-central-1.compute.internal --patch &lt;span class="s1"&gt;&amp;#39;{ &amp;#34;metadata&amp;#34;: { &amp;#34;annotations&amp;#34;: { &amp;#34;machineconfiguration.openshift.io/currentConfig&amp;#34;: &amp;#34;rendered-worker-5baefb5bb7ad1d69cd7a0c3dc52ef2f3&amp;#34; } } }&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Watch the MachineConfigPool&lt;/p&gt;
&lt;div class="src src-shell"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ oc get mcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Wait for the config rollout to complete.&lt;/p&gt;</description></item><item><title>Overview of Red Hat's Multi Cloud Gateway (Noobaa)</title><link>https://blog.stderr.at/openshift-platform/day-2/storage/2022-04-22-multi-cloud-gateway/</link><pubDate>Fri, 22 Apr 2022 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/day-2/storage/2022-04-22-multi-cloud-gateway/</guid><description>
&lt;p&gt;
This is my personal summary of experimenting with Red Hat&amp;#39;s Multi
Cloud Gateway (MCG) based on the upstream &lt;a href="https://www.noobaa.io/"&gt;Noobaa&lt;/a&gt; project. MCG is part
of Red Hat&amp;#39;s OpenShift Data Foundation (ODF). ODF bundles the upstream
projects &lt;a href="https://ceph.io/en/"&gt;Ceph&lt;/a&gt; and &lt;a href="https://noobaa.io"&gt;Noobaa&lt;/a&gt;.&lt;/p&gt;
&lt;div id="outline-container-headline-1" class="outline-2"&gt;
&lt;h2 id="headline-1"&gt;
Overview
&lt;/h2&gt;
&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;
&lt;p&gt;
Noobaa, or the Multicloud Gateway (MCG), is a S3 based data federation
tool. It allows you to use S3 backends from various sources and&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sync&lt;/li&gt;
&lt;li&gt;replicate&lt;/li&gt;
&lt;li&gt;or simply use existing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;S3 buckets. Currently the following sources, or backing stores are supported:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS S3&lt;/li&gt;
&lt;li&gt;Azure Blob&lt;/li&gt;
&lt;li&gt;Google Cloud Storage&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Any other S3 compatible storage, for example&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ceph&lt;/li&gt;
&lt;li&gt;Minio&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Noobaa also supports using a local file system as a backing store for S3.&lt;/p&gt;
&lt;p&gt;
The main purpose is to provide a single API endpoint for applications
using various S3 backends.&lt;/p&gt;
&lt;p&gt;
One of the main features of Noobaa is the storage pipeline. With a
standard Noobaa S3 bucket, when storing a new Object Noobaa executes
the following steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chunking of the Object&lt;/li&gt;
&lt;li&gt;De-duplication&lt;/li&gt;
&lt;li&gt;Compression&lt;/li&gt;
&lt;li&gt;and Encryption&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means that data stored in public cloud S3 offerings is
automatically encrypted. Noobaa also supports using Hashicorp &lt;a href="https://www.hashicorp.com/products/vault"&gt;Vault&lt;/a&gt;
for storing and retrieving encryption keys.&lt;/p&gt;
&lt;p&gt;
If you need to skip the storage pipeline, Noobaa also supports
namespace buckets. For example these type of buckets allow you to
write directly to AWS S3 and retrieve Objects via Noobaa. Or it could
be used to migrate buckets from one cloud provider to another.&lt;/p&gt;
&lt;p&gt;
Noobaa also has support for triggering JavaScript based function when&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;creating new objects&lt;/li&gt;
&lt;li&gt;reading existing objects&lt;/li&gt;
&lt;li&gt;deleting objects&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-2" class="outline-2"&gt;
&lt;h2 id="headline-2"&gt;
Setup
&lt;/h2&gt;
&lt;div id="outline-text-headline-2" class="outline-text-2"&gt;
&lt;p&gt;
With OpenShift Plus or an OpenShift Data Foundation subscription you
can use the OpenShift Data Foundation Operator.&lt;/p&gt;
&lt;p&gt;
For testing Noobaa we used the standalone installation method
&lt;span style="text-decoration: underline;"&gt;without&lt;/span&gt; setting up Ceph storage (see &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_openshift_data_foundation/4.10/html/deploying_openshift_data_foundation_using_amazon_web_services/deploy-standalone-multicloud-object-gateway"&gt;here&lt;/a&gt;). OpenShift was running in
AWS for testing.&lt;/p&gt;
&lt;p&gt;
If you would like to use the upstream version you can use the Noobaa
operator (&lt;a href="https://github.com/noobaa/noobaa-operator"&gt;https://github.com/noobaa/noobaa-operator&lt;/a&gt;). This is what the
OpenShift Data Foundation (ODF) is using as well.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-3" class="outline-2"&gt;
&lt;h2 id="headline-3"&gt;
Command line interface
&lt;/h2&gt;
&lt;div id="outline-text-headline-3" class="outline-text-2"&gt;
&lt;p&gt;
Noobaa also comes with a command line interface &lt;code&gt;noobaa&lt;/code&gt;. It&amp;#39;s
available via an ODF subscription or can be installed separately. See
the noobaa-operator &lt;a href="https://github.com/noobaa/noobaa-operator/blob/master/README.md"&gt;readme&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-4" class="outline-2"&gt;
&lt;h2 id="headline-4"&gt;
Resources
&lt;/h2&gt;
&lt;div id="outline-text-headline-4" class="outline-text-2"&gt;
&lt;p&gt;
Before using an S3 object store with Noobaa we need to create so
called &lt;span style="text-decoration: underline;"&gt;Resources&lt;/span&gt;. This can be done via the Noobaa user interface or
via the command line. For example the following commands create a new
Resource using an AWS S3 bucket as a backing store&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# create an S3 bucket in eu-north-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3api create-bucket &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --region eu-north-1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --bucket tosmi-eu-north-1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --create-bucket-configuration &lt;span class="nv"&gt;LocationConstraint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eu-north-1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# create an S3 bucket in eu-north-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3api create-bucket &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --region eu-west-1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --bucket tosmi-eu-west-1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --create-bucket-configuration &lt;span class="nv"&gt;LocationConstraint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eu-west-1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# create Noobaa backing store using the tosmi-eu-north-1 bucket above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;noobaa backingstore create aws-s3 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --region eu-north-1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --target-bucket tosmi-eu-north-1 aws-eu-north
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# create Noobaa backing store using the tosmi-eu-west-1 bucket above&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;noobaa backingstore create aws-s3 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --region eu-west-1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --target-bucket tosmi-eu-west-1 aws-eu-west&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Or if we would like to use Azure blob&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# create two resource groups for storage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az group create --location northeurope -g mcg-northeurope
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# create two storage accounts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az storage account create --name mcgnortheurope -g mcg-northeurope --location northeurope --sku Standard_LRS --kind StorageV2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# create containers for storing blobs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az storage container create --account-name mcgnortheurope -n mcg-northeurope
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# list storage account keys for noobaa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az storage account list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az storage account show -g mcg-northeurope -n mcgnortheurope
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az storage account keys list -g mcg-westeurope -n mcgwesteurope
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az storage account keys list -g mcg-northeurope -n mcgnortheurope
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;noobaa backingstore create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; azure-blob azure-northeurope &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --account-key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;the key&amp;gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --account-name&lt;span class="o"&gt;=&lt;/span&gt;mcgnortheurope &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; --target-blob-container&lt;span class="o"&gt;=&lt;/span&gt;mcg-northeurope&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Using&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;noobaa backingstore list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
we are able to confirm that our stores were created successfully.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-5" class="outline-2"&gt;
&lt;h2 id="headline-5"&gt;
Buckets
&lt;/h2&gt;
&lt;div id="outline-text-headline-5" class="outline-text-2"&gt;
&lt;p&gt;
After creating the backend stores we are able to create Buckets and define the
layout of backends.&lt;/p&gt;
&lt;p&gt;
There are two ways how to create buckets, either directly via the Noobaa UI,
or using Kubernetes (K8s) objects.&lt;/p&gt;
&lt;p&gt;
We will focus on using K8s objects in this post.&lt;/p&gt;
&lt;div id="outline-container-headline-6" class="outline-3"&gt;
&lt;h3 id="headline-6"&gt;
Required K8s objects
&lt;/h3&gt;
&lt;div id="outline-text-headline-6" class="outline-text-3"&gt;
&lt;p&gt;
The Noobaa operator provides the following Custom Resource Definitions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BackingStore&lt;/code&gt;: we already created &lt;code&gt;BackingStores&lt;/code&gt; in the Resources
section&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BucketClass&lt;/code&gt;: a bucket class defines the layout of our bucket
(single, mirrored or tiered)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StorageClass&lt;/code&gt;: a standard K8s &lt;code&gt;StorageClass&lt;/code&gt; referencing the &lt;code&gt;BucketClass&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ObjectBucketClaim&lt;/code&gt;: A OBC or &lt;code&gt;ObjectBucketClaim&lt;/code&gt; creates the bucket
for us in Noobaa. Additionally the Noobaa operator creates a
&lt;code&gt;ConfigMap&lt;/code&gt; and a &lt;code&gt;Secret&lt;/code&gt; with the same name as the Bucket, storing
access details (&lt;code&gt;ConfigMap&lt;/code&gt;) and credentials (&lt;code&gt;Secret&lt;/code&gt;) for accessing
the bucket.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-7" class="outline-3"&gt;
&lt;h3 id="headline-7"&gt;
BucketClass
&lt;/h3&gt;
&lt;div id="outline-text-headline-7" class="outline-text-3"&gt;
&lt;p&gt;
Let&amp;#39;s create a example &lt;code&gt;BucketClass&lt;/code&gt; which mirrors objects between the
AWS S3 buckets eu-west-1 and eu-north-1.&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;noobaa.io/v1alpha1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;BucketClass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;noobaa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-bucket-class&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;openshift-storage&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;placementPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tiers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;backingStores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;aws-eu-north&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;aws-eu-west&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;placement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Mirror&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
So we are defining a &lt;code&gt;BucketClass&lt;/code&gt; &lt;span style="text-decoration: underline;"&gt;aws-mirrored-bucket-class&lt;/span&gt; that
has the following placement policy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A single tier with one backing store&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The backing store uses two AWS buckets&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;aws-eu-north&lt;/li&gt;
&lt;li&gt;aws-eu-west&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The placement policy is mirror, so all objects uploaded to buckets
using this &lt;code&gt;BucketClass&lt;/code&gt; will be mirrored between &lt;span style="text-decoration: underline;"&gt;aws-eu-north&lt;/span&gt; and
&lt;span style="text-decoration: underline;"&gt;aws-eu-west&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A &lt;code&gt;BucketClass&lt;/code&gt; could have multiple tiers, moving cold data
transparently to a lower tier, but let&amp;#39;s keep this simple.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-8" class="outline-3"&gt;
&lt;h3 id="headline-8"&gt;
StorageClass
&lt;/h3&gt;
&lt;div id="outline-text-headline-8" class="outline-text-3"&gt;
&lt;p&gt;
After creating our &lt;code&gt;BucketClass&lt;/code&gt; we are now able to define a standard
K8s &lt;code&gt;StorageClass&lt;/code&gt;:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;storage.k8s.io/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;StorageClass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;annotations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Provides Mirrored Object Bucket Claims (OBCs) in AWS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-openshift-storage.noobaa.io&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;bucketclass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-bucket-class&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;provisioner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;openshift-storage.noobaa.io/obc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;reclaimPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Delete&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;volumeBindingMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Immediate&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
This &lt;code&gt;StorageClass&lt;/code&gt; uses our &lt;code&gt;BucketClass&lt;/code&gt; &lt;span style="text-decoration: underline;"&gt;aws-mirrored-bucket-class&lt;/span&gt;
as a backend. All buckets created leveraging this &lt;code&gt;StorageClass&lt;/code&gt; will
mirror data between &lt;span style="text-decoration: underline;"&gt;aws-eu-north&lt;/span&gt; and &lt;span style="text-decoration: underline;"&gt;aws-eu-west&lt;/span&gt; (see the previous
chapter).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-9" class="outline-3"&gt;
&lt;h3 id="headline-9"&gt;
ObjectBucketClaim
&lt;/h3&gt;
&lt;div id="outline-text-headline-9" class="outline-text-3"&gt;
&lt;p&gt;
Finally we are able to create &lt;code&gt;ObjectBucketClaims&lt;/code&gt; for projects
requiring object storage. An &lt;code&gt;ObjectBucketClaim&lt;/code&gt; is similar to an
&lt;code&gt;PersistentVolumeClaim&lt;/code&gt;. Every time a claim is created the Noobaa
operator will create a corresponding S3 bucket for us.&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s start testing this out by creating a new OpenShift project&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;oc new-project obc-test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Now we define a &lt;code&gt;ObjectBucketClaim&lt;/code&gt; to create a new bucket for our application:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;objectbucket.io/v1alpha1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ObjectBucketClaim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;noobaa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-claim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;generateBucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;storageClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-openshift-storage.noobaa.io&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We use the &lt;code&gt;StorageClass&lt;/code&gt; created in the previous step. This will create&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a S3 Bucket in the requested &lt;code&gt;StorageClass&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;ConfigMap&lt;/code&gt; storing access information&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;Secret&lt;/code&gt; storing credentials for accessing the S3 Bucket&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For testing we will upload some data via &lt;a href="https://s3tools.org/s3cmd"&gt;&lt;span style="text-decoration: underline;"&gt;s3cmd&lt;/span&gt;&lt;/a&gt; and use a pod to monitor
data within the bucket.&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s do the upload with &lt;span style="text-decoration: underline;"&gt;s3cmd&lt;/span&gt;, we need the following config file:&lt;/p&gt;
&lt;div class="src src-ini"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[default]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;check_ssl_certificate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;check_ssl_hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;access_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;access key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;secret_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;secret key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;host_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;s3-openshift-storage.apps.ocp.aws.tntinfra.net&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;host_bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;%(bucket).s3-openshift-storage.apps.ocp.aws.tntinfra.net&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Of course you must change &lt;span style="text-decoration: underline;"&gt;host-base&lt;/span&gt; according to your cluster
name. It&amp;#39;s a route in the &lt;span style="text-decoration: underline;"&gt;openshift-storage&lt;/span&gt; namespace:&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;oc get route -n openshift-storage s3 -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.spec.host}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
You can extract the access and secret key from the
K8s secret via:&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;oc extract secret/aws-mirrored-claim --to&lt;span class="o"&gt;=&lt;/span&gt;-&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Copy the access key and the secret key to the s3 command config file
(we&amp;#39;ve called our config &lt;span style="text-decoration: underline;"&gt;noobaa-s3.cfg&lt;/span&gt;). Now we can list all
available buckets via:&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ s3cmd ls -c noobaa-s3.cfg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2022-04-22 13:56 s3://aws-mirrored-c1087a17-5c84-4c62-9f36-29081a6cf5a4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Now we are going to upload a sample file:&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ s3cmd -c noobaa-s3.cfg put simple-aws-mirrored-obc.yaml s3://aws-mirrored-c1087a17-5c84-4c62-9f36-29081a6cf5a4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;upload: &lt;span class="s1"&gt;&amp;#39;simple-aws-mirrored-obc.yaml&amp;#39;&lt;/span&gt; -&amp;gt; &lt;span class="s1"&gt;&amp;#39;s3://aws-mirrored-c1087a17-5c84-4c62-9f36-29081a6cf5a4/simple-aws-mirrored-obc.yaml&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; of 1&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;226&lt;/span&gt; of &lt;span class="m"&gt;226&lt;/span&gt; 100% in 0s 638.18 B/s &lt;span class="k"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We can also list available files via&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;s3cmd -c noobaa-s3.cfg ls s3://aws-mirrored-c1087a17-5c84-4c62-9f36-29081a6cf5a4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2022-04-22 13:57 &lt;span class="m"&gt;226&lt;/span&gt; s3://aws-mirrored-c1087a17-5c84-4c62-9f36-29081a6cf5a4/simple-aws-mirrored-obc.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Our we could use a &lt;code&gt;Pod&lt;/code&gt; to list available files from within
OpenShift. Note how we use the &lt;code&gt;ConfigMap&lt;/code&gt; and the &lt;code&gt;Secret&lt;/code&gt; the Noobaa
operater created for us, when we created the &lt;code&gt;ObjectBucketClaim&lt;/code&gt;:&lt;/p&gt;
&lt;div class="src src-yaml"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;batch/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Job&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;s3-test-job&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;s3-pod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;d3fk/s3cmd:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;s3-pod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;valueFrom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;configMapKeyRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-claim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;BUCKET_HOST&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;valueFrom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;configMapKeyRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-claim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;BUCKET_HOST&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;BUCKET_PORT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;valueFrom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;configMapKeyRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-claim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;BUCKET_PORT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;valueFrom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;secretKeyRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-claim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;valueFrom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;secretKeyRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;aws-mirrored-claim&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/bin/sh&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- -&lt;span class="l"&gt;c&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;s3cmd --host $BUCKET_HOST --host-bucket &amp;#34;%(bucket).$BUCKET_HOST&amp;#34; --no-check-certificate ls s3://$BUCKET_NAME&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restartPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Never&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
That&amp;#39;s all for now. If time allows we are going to write a follow up blog post on&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replicating Buckets and&lt;/li&gt;
&lt;li&gt;Functions&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Adventures in Java Land: JPA disconnected entities</title><link>https://blog.stderr.at/integrations/java/2022-02-25-jpa-disconnected-entity/</link><pubDate>Fri, 25 Feb 2022 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/integrations/java/2022-02-25-jpa-disconnected-entity/</guid><description>&lt;p&gt;
An old man tries to refresh his Java skills and does &lt;a href="https://www.redhat.com/en/services/training/red-hat-cloud-native-microservices-development-quarkus-do378"&gt;DO378&lt;/a&gt;. He fails
spectacularly at the first real example but learns a lot on the way.&lt;/p&gt;
&lt;div id="outline-container-headline-1" class="outline-2"&gt;
&lt;h2 id="headline-1"&gt;
The exception
&lt;/h2&gt;
&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;
&lt;p&gt;
There is this basic example where you build a minimal REST API for
storing speaker data in a database. Quarkus makes this quite easy. You
just have to define your database connection properties in
&lt;code&gt;resources/application.properties&lt;/code&gt; and off you go developing your Java
Quarkus REST service:&lt;/p&gt;
&lt;div class="src src-ini"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;quarkus.datasource.db-kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;h2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;quarkus.datasource.jdbc.url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;jdbc:h2:mem:default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;quarkus.datasource.username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;quarkus.hibernate-orm.database.generation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;drop-and-create&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;quarkus.hibernate-orm.log.sql&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
So next we define our entity class to be stored in the database. I
will skip the import statements and any other code not relevant for
this post.&lt;/p&gt;
&lt;div class="src src-java"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// import statements skipped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PanacheEntity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nameFirst&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nameLast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;organization&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@JsonbTransient&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;biography&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;picture&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;twitterHandle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Constructors, getters and setters, toString and other methods skipped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;....&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We define an entity &lt;code&gt;Speaker&lt;/code&gt; which extends the &lt;a href="https://github.com/quarkusio/quarkus/blob/main/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/PanacheEntity.java"&gt;&lt;code&gt;PanacheEntity&lt;/code&gt;&lt;/a&gt;
class. &lt;a href="https://quarkus.io/guides/hibernate-orm-panache"&gt;Panache&lt;/a&gt; is a thin wrapper around &lt;a href="https://hibernate.org/"&gt;Hibernate&lt;/a&gt; providing convince
features. For example the base class &lt;code&gt;PanacheEntity&lt;/code&gt; defines a
autoincrement &lt;code&gt;Id&lt;/code&gt; column for us. This inherited &lt;code&gt;Id&lt;/code&gt; column is of
importance for understanding the problem ahead of us.&lt;/p&gt;
&lt;p&gt;
So next you define your &lt;code&gt;SpeakerService&lt;/code&gt; class which uses the
entity. Once again I will skip the imports and any code not relevant
for understanding the problem:&lt;/p&gt;
&lt;div class="src src-java"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// imports omitted&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpeakerService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// other code omitted&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
We focus on the &lt;code&gt;create&lt;/code&gt; method here because the call to
&lt;code&gt;speaker.persist()&lt;/code&gt; was the reason for all the headache.&lt;/p&gt;
&lt;p&gt;
But we are still in coding mode and last but not least we define our
&lt;code&gt;SpeakerResource&lt;/code&gt; class, again everything not relevant for
understanding the problem was removed:&lt;/p&gt;
&lt;div class="src src-java"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// import statements omitted&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/speaker&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nd"&gt;@Consumes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpeakerResource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Inject&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SpeakerService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// other code omitted&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@POST&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Transactional&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newSpeaker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newSpeaker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newSpeaker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
The root path for our &lt;code&gt;SpeakerResource&lt;/code&gt; is &lt;span style="text-decoration: underline;"&gt;/speaker&lt;/span&gt;. We inject the
&lt;code&gt;SpeakerService&lt;/code&gt; and define a method &lt;code&gt;create()&lt;/code&gt; for creating a &lt;code&gt;Speaker&lt;/code&gt;. We
would like to be able to send &lt;code&gt;@Post&lt;/code&gt; requests to this endpoint and &lt;a href="https://javaee.github.io/jsonb-spec/"&gt;Jsonb&lt;/a&gt;
or&lt;a href="https://github.com/FasterXML/jackson"&gt; Jackson,&lt;/a&gt; whichever we currently prefer, will deserialize the JSON
body in a &lt;code&gt;Speaker&lt;/code&gt; object for us.&lt;/p&gt;
&lt;p&gt;
Splendid, time to switch from coding mode to testing.&lt;/p&gt;
&lt;p&gt;
We launch that Quarkus application in developer mode&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mvn quarkus:dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Quarkus is so friendly and provides a swagger-ui in dev mode for testing
our endpoint. Super duper lets call the &lt;code&gt;create()&lt;/code&gt; endpoint via Swagger:&lt;/p&gt;
&lt;p&gt;
&lt;img src="https://blog.stderr.at/integrations/java/images/swagger_post_500.png" alt="/integrations/java/images/swagger_post_500.png" title="/integrations/java/images/swagger_post_500.png" /&gt;&lt;/p&gt;
&lt;p&gt;
Because we are lazy we accept the default Swagger provides for us and
just click &lt;span style="text-decoration: underline;"&gt;Execute&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;
BOOM, 500 internal server error. And a beautiful Java exception:&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;org.jboss.resteasy.spi.UnhandledException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: org.acme.conference.speaker.Speaker&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
What? Detached entity what does this mean and why?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-2" class="outline-2"&gt;
&lt;h2 id="headline-2"&gt;
Enlightenment
&lt;/h2&gt;
&lt;div id="outline-text-headline-2" class="outline-text-2"&gt;
&lt;p&gt;
Behind the scenes &lt;a href="https://hibernate.org"&gt;Hibernate&lt;/a&gt; uses a so called EntityManager for
managing entities. An Entity can be in the following states when
managed by Hibernate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NEW: The entity object was just created and is not persisted to the database&lt;/li&gt;
&lt;li&gt;MANAGED: The entity is managed by a running Session and all changes
to the entity will be propagated to the database. After call to
&lt;code&gt;entitymanager.persist()&lt;/code&gt; or in our case &lt;code&gt;newSpeaker.persist()&lt;/code&gt; the
entity is stored in the database and in the &lt;code&gt;managed&lt;/code&gt; state.&lt;/li&gt;
&lt;li&gt;REMOVED: The entity is removed from the database. And finally&lt;/li&gt;
&lt;li&gt;DETACHED: The Entity was detached from the EntityManager, e.g. by
calling &lt;code&gt;entitymanager.detach()&lt;/code&gt; or &lt;code&gt;entitymanager.close()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href="https://www.baeldung.com/hibernate-entity-lifecycle"&gt;this&lt;/a&gt; blog for a way better explanation what is going on with
entity states.&lt;/p&gt;
&lt;p&gt;
Ok, cool but why the hell is our &lt;code&gt;Speaker&lt;/code&gt; entity in the &lt;span style="text-decoration: underline;"&gt;DETACHED&lt;/span&gt;
state? It was just created and never saved to the database before!&lt;/p&gt;
&lt;p&gt;
After checking the database (was empty), I started my Java debugger of
choice (IntellJ, but use whatever fit&amp;#39;s your needs. I&amp;#39;m to old for IDE
vs Editor and Editor vs Editor wars).&lt;/p&gt;
&lt;p&gt;
So looking at the &lt;code&gt;Speaker&lt;/code&gt; entity before calling &lt;code&gt;persist()&lt;/code&gt; revealed the following:&lt;/p&gt;
&lt;p&gt;
&lt;img src="https://blog.stderr.at/integrations/java/images/speaker_object_debugger.png" alt="/integrations/java/images/speaker_object_debugger.png" title="/integrations/java/images/speaker_object_debugger.png" /&gt;&lt;/p&gt;
&lt;p&gt;
The &lt;code&gt;Speaker&lt;/code&gt; object passed into &lt;code&gt;create()&lt;/code&gt; has an &lt;span style="text-decoration: underline;"&gt;Id&lt;/span&gt; of 0 and all
the internal Hibernate fields are set to null. So this seems to
indicate that this &lt;code&gt;Speaker&lt;/code&gt; object is currently not attached to an
&lt;code&gt;EntityManager&lt;/code&gt; session. This might explain the &lt;strong&gt;DETACHED&lt;/strong&gt; state.&lt;/p&gt;
&lt;p&gt;
I started playing around with &lt;code&gt;EntityManager&lt;/code&gt; and calling &lt;code&gt;merge()&lt;/code&gt; on the
speaker object. The code looked like this:&lt;/p&gt;
&lt;div class="src src-java"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpeakerService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Inject&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EntityManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// lots of code skipped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newSpeaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;em&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newSpeaker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Looking at the &lt;code&gt;newSpeaker&lt;/code&gt; object returned by calling &lt;code&gt;entitymanager.merge()&lt;/code&gt;
in the debugger revealed the following:&lt;/p&gt;
&lt;p&gt;
&lt;img src="https://blog.stderr.at/integrations/java/images/speaker_object_entitymanager_debugger.png" alt="/integrations/java/images/speaker_object_entitymanager_debugger.png" title="/integrations/java/images/speaker_object_entitymanager_debugger.png" /&gt;&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;newSpeaker&lt;/code&gt; has an Id of 1 (hm, why no 0?) and some those special
Hibernate fields starting with $$ have a value assigned. So for me
this indicates that the object is now managed by an &lt;code&gt;EntityManager&lt;/code&gt;
session and in the &lt;strong&gt;MANAGED&lt;/strong&gt; state.&lt;/p&gt;
&lt;p&gt;
And the &lt;code&gt;Id&lt;/code&gt;, already assigned to the original &lt;code&gt;Speaker&lt;/code&gt; object,
de-serialized form JSON is actually the reason for the beautiful
exception above.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-3" class="outline-2"&gt;
&lt;h2 id="headline-3"&gt;
Explanation
&lt;/h2&gt;
&lt;div id="outline-text-headline-3" class="outline-text-2"&gt;
&lt;p&gt;
So after a little bit of internet search magic I found an explanation
for the exception:&lt;/p&gt;
&lt;p&gt;
&lt;div class="admonitionblock important" &gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="icon"&gt;&lt;i class="fa icon-important" title="important"&gt;&lt;/i&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;p&gt;
If an &lt;code&gt;Id&lt;/code&gt; is already assigned to an entity object, Hibernate assumes
that this is an entity in the &lt;strong&gt;DETACHED&lt;/strong&gt; state (if the &lt;span style="text-decoration: underline;"&gt;Id&lt;/span&gt; is
auto-generated). For an entity to be persisted to the database it has
to be transferred in the &lt;strong&gt;MANAGED&lt;/strong&gt; state by calling
&lt;code&gt;entitymanager.merge()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
For more information see the &lt;a href="https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#pc"&gt;Hibernate documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;
We can only call &lt;code&gt;persist()&lt;/code&gt; if the object is in the transient state,
to quote the &lt;a href="https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#pc"&gt;Hibernate documentation&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;
&lt;span style="text-decoration: underline;"&gt;transient&lt;/span&gt;: the entity has just been instantiated and is not associated
with a persistence context. It has no persistent representation in the
database and &lt;strong&gt;typically no identifier value has been assigned (unless
the assigned generator was used)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
And reading on we also get explanation for the detached state:&lt;/p&gt;
&lt;p&gt;
&lt;span style="text-decoration: underline;"&gt;detached&lt;/span&gt;: &lt;strong&gt;the entity has an associated identifier&lt;/strong&gt; but is no longer
associated with a persistence context (usually because the persistence
context was closed or the instance was evicted from the context)&lt;/p&gt;
&lt;p&gt;
Just removing the &lt;code&gt;Id&lt;/code&gt; from the POST request will solve the issue and
the example started to work.&lt;/p&gt;
&lt;p&gt;
This is also why the &lt;code&gt;Id&lt;/code&gt; column is different in the &lt;code&gt;Speaker&lt;/code&gt; object
(deserialized from JSON) and &lt;code&gt;newSpeaker&lt;/code&gt; object (create by calling
&lt;code&gt;entitymanager.merge()&lt;/code&gt;). The &lt;code&gt;Speaker&lt;/code&gt; &lt;span style="text-decoration: underline;"&gt;Id&lt;/span&gt; got passed in from JSON,
and has nothing to do with the auto generated primary key &lt;span style="text-decoration: underline;"&gt;Id&lt;/span&gt; within
our database. After calling &lt;code&gt;entitymanager.merge()&lt;/code&gt; the entity is
actually associated with a database session and the &lt;span style="text-decoration: underline;"&gt;Id&lt;/span&gt; is
auto generated.&lt;/p&gt;
&lt;p&gt;
So maybe this is basic stuff, but it took me quite a few hours to
understand what was going on.&lt;/p&gt;
&lt;p&gt;
Maybe this is also a bad example. Should one expose the &lt;code&gt;Id&lt;/code&gt; if it is
auto generated and only used internally? Or the code just needs to
handle that case… But this needs me more learning about API design.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Stumbling into Azure Part II: Setting up a private ARO cluster</title><link>https://blog.stderr.at/integrations/azure/2021-10-29-private-aro/</link><pubDate>Fri, 29 Oct 2021 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/integrations/azure/2021-10-29-private-aro/</guid><description>&lt;p&gt;
In Part I of our blog post we covered setting up required resources in
Azure. Now we are finally going to set up a private cluster. Private&lt;/p&gt;
&lt;p&gt;
As review from Part I here is our planned setup, this time including
the ARO cluster.&lt;/p&gt;
&lt;div id="outline-container-headline-1" class="outline-2"&gt;
&lt;h2 id="headline-1"&gt;
Azure Setup
&lt;/h2&gt;
&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;
&lt;p&gt;
The diagram below depicts our planned setup:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.stderr.at/integrations/azure/images/azure_network_setup_with_aro.png" alt="/integrations/azure/images/azure_network_setup_with_aro.png" title="/integrations/azure/images/azure_network_setup_with_aro.png" /&gt;&lt;/p&gt;
&lt;p&gt;
On the right hand side can see the resources required for our lab:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a virtual network (vnet 192.168.128.0/19). This vnet will be split
into 3 separate subnets&lt;/li&gt;
&lt;li&gt;a master subnet (192.168.129.0/24) holding the ARO control plane nodes&lt;/li&gt;
&lt;li&gt;a node subnet (192.168.130.0/24) holding ARO worker nodes&lt;/li&gt;
&lt;li&gt;and finally a subnet call &lt;code&gt;GatewaySubnet&lt;/code&gt; where we are going to
deploy our Azure VPN gateway (called a &lt;code&gt;vnet-gateway&lt;/code&gt;)
&lt;div class="admonitionblock warning" &gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="icon"&gt;&lt;i class="fa icon-warning" title="warning"&gt;&lt;/i&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;p&gt;
The subnet where the Azure VPN gateway is located needs to have
the name &lt;code&gt;GatewaySubnet&lt;/code&gt;. Otherwise creating the Azure VPN gateway
will fail.&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;we also need a &lt;code&gt;publicIP&lt;/code&gt; resource that we are going to connect to
our &lt;code&gt;vnet-gateway&lt;/code&gt; (the VPN gateway)&lt;/li&gt;
&lt;li&gt;and finally a &lt;code&gt;local-gateway&lt;/code&gt; resource that tells the
&lt;code&gt;vnet-gateway&lt;/code&gt; which networks are reachable on the left, in our
case the Hetzner server.&lt;/li&gt;
&lt;/ul&gt;
&lt;div id="outline-container-headline-2" class="outline-3"&gt;
&lt;h3 id="headline-2"&gt;
Creating the private Azure Red Hat OpenShift cluster
&lt;/h3&gt;
&lt;div id="outline-text-headline-2" class="outline-text-3"&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Register required resource providers&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az provider register -n Microsoft.RedHatOpenShift --wait
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az provider register -n Microsoft.Compute --wait
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az provider register -n Microsoft.Storage --wait
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az provider register -n Microsoft.Authorization --wait&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First we are going to set some environment variable. Those
variables are used in the upcoming commands:&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;RESOURCEGROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;aro-rg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CLUSTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aro1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GATWAY_SUBNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;192.168.128.0/24&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;MASTER_SUBNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;192.168.129.0/24&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;WORKER_SUBNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;192.168.130.0/24&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;HETZNER_VM_NETWORKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.0.0.0/24 192.168.122.0/24 172.16.100.0/24&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Disable subnet private endpoint policies&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network vnet subnet update &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name master-subnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--vnet-name aro-vnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--disable-private-link-service-network-policies true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a private DNS zone for our cluster&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network private-dns zone create -n private2.tntinfra.net -g aro-rg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the cluster&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az aro create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name &lt;span class="nv"&gt;$CLUSTER&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--vnet aro-vnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--master-subnet master-subnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--worker-subnet worker-subnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--apiserver-visibility Private &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--ingress-visibility Private &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--domain private.tntinfra.net
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --pull-secret @pull-secret.txt # [OPTIONAL]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After successful cluster creating add DNS entry for the API and Ingress&lt;/p&gt;
&lt;p&gt;
Query the Azure API for the API server IP and the ingress IP addresses:&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az aro show -n aro1 -g aro-rg --query &amp;#39;{api:apiserverProfile.ip, ingress:ingressProfiles[0].ip}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Example output&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Api Ingress
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;------------- ---------------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.129.4 192.168.130.254&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Add entries to Azure private DNS&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network private-dns record-set a add-record -g aro-rg -z private.tntinfra.net -a &lt;span class="s2"&gt;&amp;#34;192.168.129.4&amp;#34;&lt;/span&gt; -n api
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network private-dns record-set a add-record -g aro-rg -z private.tntinfra.net -a &lt;span class="s2"&gt;&amp;#34;192.168.130.254&amp;#34;&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;#34;*.apps&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
List entries to verify configuration&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network private-dns record-set a list -g aro-rg -z private.tntinfra.net&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Output:&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Name ResourceGroup Ttl Type AutoRegistered Metadata
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;------ --------------- ----- ------ ---------------- ----------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;api aro-rg &lt;span class="m"&gt;3600&lt;/span&gt; A False
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*.apps aro-rg &lt;span class="m"&gt;3600&lt;/span&gt; A False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;List cluster credentials after successful setup&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az aro list-credentials &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name &lt;span class="nv"&gt;$CLUSTER&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get the console URL&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az aro show &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name &lt;span class="nv"&gt;$CLUSTER&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--query &lt;span class="s2"&gt;&amp;#34;consoleProfile.url&amp;#34;&lt;/span&gt; -o tsv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-3" class="outline-2"&gt;
&lt;h2 id="headline-3"&gt;
DNS, curl
&lt;/h2&gt;
&lt;div id="outline-text-headline-3" class="outline-text-2"&gt;
&lt;p&gt;
this works, dunno why?&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig @192.168.129.7 console-openshift-console.apps.xm7rdz4r.westeurope.aroapp.io&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
use &lt;span style="text-decoration: underline;"&gt;curl&lt;/span&gt; to access the internal API and see if it works:&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -kv https://192.168.129.4:6443&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-4" class="outline-2"&gt;
&lt;h2 id="headline-4"&gt;
Additional Resources
&lt;/h2&gt;
&lt;div id="outline-text-headline-4" class="outline-text-2"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.notnot.ninja/2020/09/19/azure-site-to-site-vpn/"&gt;Build an Azure site-to-site VPN for DevTest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-howto-site-to-site-resource-manager-cli"&gt;Create a virtual network with a Site-to-Site VPN connection using CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libreswan.org/wiki/FAQ#Why_is_it_recommended_to_disable_rp_filter_in_.2Fproc.2Fsys.2Fnet_.3F"&gt;Libreswan: Disable rp_filter for IPsec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libreswan.org/wiki/FAQ#NAT_.2B_IPsec_is_not_working"&gt;Libreswan: NAT and IPsec not working&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libreswan.org/wiki/Subnet_to_subnet_VPN"&gt;Libreswan: Subnet to subnet VPN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Stumbling into Azure Part I: Building a site-to-site VPN tunnel for testing</title><link>https://blog.stderr.at/integrations/azure/2021-10-17-s2s-vpn/</link><pubDate>Sat, 16 Oct 2021 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/integrations/azure/2021-10-17-s2s-vpn/</guid><description>&lt;p&gt;
So we want to play with ARO (Azure Red Hat OpenShift) private
clusters. A private cluster is &lt;strong&gt;not&lt;/strong&gt; reachable from the internet
(surprise) and is only reachable via a VPN tunnel from other networks.&lt;/p&gt;
&lt;p&gt;
This blog post describes how we created a site-to-site VPN between a
Hetzner dedicated server running multiple VM&amp;#39;s via libvirt and Azure.&lt;/p&gt;
&lt;p&gt;
An upcoming blog post is going to cover the setup of the private ARO
cluster.&lt;/p&gt;
&lt;div id="outline-container-headline-1" class="outline-2"&gt;
&lt;h2 id="headline-1"&gt;
Azure Setup
&lt;/h2&gt;
&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;
&lt;p&gt;
The diagram below depicts our planned setup:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.stderr.at/integrations/azure/images/azure_network_setup.png" alt="/integrations/azure/images/azure_network_setup.png" title="/integrations/azure/images/azure_network_setup.png" /&gt;&lt;/p&gt;
&lt;p&gt;
On the right hand side can see the resources required for our lab:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a virtual network (vnet 192.168.128.0/19). This vnet will be split
into 3 separate subnets&lt;/li&gt;
&lt;li&gt;a master subnet (192.168.129.0/24) holding the ARO control plane nodes&lt;/li&gt;
&lt;li&gt;a node subnet (192.168.130.0/24) holding ARO worker nodes&lt;/li&gt;
&lt;li&gt;and finally a subnet call &lt;code&gt;GatewaySubnet&lt;/code&gt; where we are going to
deploy our Azure VPN gateway (called a &lt;code&gt;vnet-gateway&lt;/code&gt;)
&lt;div class="admonitionblock warning" &gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="icon"&gt;&lt;i class="fa icon-warning" title="warning"&gt;&lt;/i&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;p&gt;
The subnet where the Azure VPN gateway is located needs to have
the name &lt;code&gt;GatewaySubnet&lt;/code&gt;. Otherwise creating the Azure VPN gateway
will fail.&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;we also need a &lt;code&gt;publicIP&lt;/code&gt; resource that we are going to connect to
our &lt;code&gt;vnet-gateway&lt;/code&gt; (the VPN gateway)&lt;/li&gt;
&lt;li&gt;and finally a &lt;code&gt;local-gateway&lt;/code&gt; resource that tells the
&lt;code&gt;vnet-gateway&lt;/code&gt; which networks are reachable on the left, in our
case the Hetzner server.&lt;/li&gt;
&lt;/ul&gt;
&lt;div id="outline-container-headline-2" class="outline-3"&gt;
&lt;h3 id="headline-2"&gt;
Creating the required Azure resources
&lt;/h3&gt;
&lt;div id="outline-text-headline-2" class="outline-text-3"&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First we are going to set some environment variable. Those
variables are used in the upcoming commands:&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;RESOURCEGROUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;aro-rg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GATWAY_SUBNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;192.168.128.0/24&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;MASTER_SUBNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;192.168.129.0/24&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;WORKER_SUBNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;192.168.130.0/24&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;HETZNER_VM_NETWORKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10.0.0.0/24 192.168.122.0/24 172.16.100.0/24&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next create a VNET resource holding our sub networks:&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network vnet create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name aro-vnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--address-prefixes 192.168.128.0/18&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the &lt;code&gt;GatewaySubnet&lt;/code&gt; subnet&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network vnet subnet create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--vnet-name aro-vnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name GatewaySubnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--address-prefixes &lt;span class="nv"&gt;$GATEWAY_SUBNET&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the master subnet&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network vnet subnet create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--vnet-name aro-vnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name master-subnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--address-prefixes &lt;span class="nv"&gt;$MASTER_SUBNET&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--service-endpoints Microsoft.ContainerRegistry&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the worker subnet&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network vnet subnet create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--vnet-name aro-vnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name worker-subnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--address-prefixes &lt;span class="nv"&gt;$WORKER_SUBNET&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--service-endpoints Microsoft.ContainerRegistry&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;public IP&lt;/code&gt; resource&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network public-ip create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name GatewayIP &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--allocation-method Dynamic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;local-gateway&lt;/code&gt; resource&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network local-gateway create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name playground &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--local-address-prefixes &lt;span class="nv"&gt;$HETZNER_VM_NETWORKS&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--gateway-ip-address 95.217.42.98&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;vnet-gateway&lt;/code&gt; resource (takes around 30 minutes)&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network vnet-gateway create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name vpn-gateway &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--public-ip-address GatewayIP &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--vnet aro-vnet &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--gateway-type Vpn &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--vpn-type RouteBased &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--sku Basic &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--no-wait&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define a &lt;code&gt;vpn-connection&lt;/code&gt;&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az network vpn-connection create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--name VNet1toSite2 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--resource-group &lt;span class="nv"&gt;$RESOURCEGROUP&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--vnet-gateway1 vpn-gateway &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--local-gateway2 playground &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--location westeurope &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt;--shared-key thepassword&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-3" class="outline-2"&gt;
&lt;h2 id="headline-3"&gt;
Required iptables (nf tables) hacks for libvirt
&lt;/h2&gt;
&lt;div id="outline-text-headline-3" class="outline-text-2"&gt;
&lt;div id="outline-container-headline-4" class="outline-3"&gt;
&lt;h3 id="headline-4"&gt;
Skip NAT rules if the destination network is in Azure and the client network deploy via libvirt
&lt;/h3&gt;
&lt;div id="outline-text-headline-4" class="outline-text-3"&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iptables -I LIBVIRT_PRT &lt;span class="m"&gt;2&lt;/span&gt; -t nat -d 192.168.129.0/24 -j RETURN
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iptables -I LIBVIRT_PRT &lt;span class="m"&gt;2&lt;/span&gt; -t nat -d 192.168.130.0/24 -j RETURN&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-5" class="outline-3"&gt;
&lt;h3 id="headline-5"&gt;
Skip NAT rules if the destination network is in Azure and the client is connected via tailscale
&lt;/h3&gt;
&lt;div id="outline-text-headline-5" class="outline-text-3"&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iptables -I ts-postrouting &lt;span class="m"&gt;1&lt;/span&gt; -t nat -d 192.168.129.0/24 -j RETURN
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iptables -I ts-postrouting &lt;span class="m"&gt;1&lt;/span&gt; -t nat -d 192.168.130.0/24 -j RETURN&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-6" class="outline-2"&gt;
&lt;h2 id="headline-6"&gt;
Libreswan setup on CentOS Stream
&lt;/h2&gt;
&lt;div id="outline-text-headline-6" class="outline-text-2"&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the Libreswan packages&lt;/p&gt;
&lt;div class="src src-h"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-h" data-lang="h"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dnf&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;libreswan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a Azure configuration for Libreswan in ~/etc/ipsec.d/azure.conf&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;conn masterSubnet
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;also=azureTunnel
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;leftsubnet=192.168.129.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rightsubnet=172.16.100.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;auto=start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;conn workerSubnet
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;also=azureTunnel
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;leftsubnet=192.168.130.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rightsubnet=172.16.100.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;auto=start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;conn azureTunnel
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;authby=secret
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;auto=start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dpdaction=restart
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dpddelay=30
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dpdtimeout=120
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ike=aes256-sha1;modp1024
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ikelifetime=3600s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ikev2=insist
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;keyingtries=3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pfs=yes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;phase2alg=aes128-sha1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;left=51.137.113.44
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;leftsubnets=192.168.128.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;right=%defaultroute
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rightsubnets=172.16.100.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;salifetime=3600s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;type=tunnel
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipsec-interface=yes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a Libreswan secrets file for Azure in &lt;code&gt;/etc/ipsec.d/azure.secrets&lt;/code&gt;:&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;%any %any : PSK &amp;#34;abc123&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable and start the IPsec service&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now ipsec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We had to explicitly load the IPsec configuration via&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipsec addconn --config /etc/ipsec.d/azure.conf azureTunnel&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-7" class="outline-2"&gt;
&lt;h2 id="headline-7"&gt;
Libreswan IPSEC debugging tips
&lt;/h2&gt;
&lt;div id="outline-text-headline-7" class="outline-text-2"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Check the state of the IPsec systemd service&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl status ipsec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check the full log of the IPsec systemd service&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;journalctl -e -u ipsec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check the state of the tunnels with the &lt;code&gt;ipsec&lt;/code&gt; command line tool&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipsec status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Check for the following lines&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; Total IPsec connections: loaded 5, active &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; State Information: DDoS cookies not required, Accepting new IKE connections
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; IKE SAs: total&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;, half-open&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt;, open&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt;, authenticated&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;, anonymous&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; IPsec SAs: total&lt;span class="o"&gt;(&lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;, authenticated&lt;span class="o"&gt;(&lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;, anonymous&lt;span class="o"&gt;(&lt;/span&gt;0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; &lt;span class="c1"&gt;#130: &amp;#34;azureTunnel/1x1&amp;#34;:500 STATE_V2_ESTABLISHED_CHILD_SA (IPsec SA established); EVENT_SA_REKEY in 2003s; newest IPSEC; eroute owner; isakmp#131; idle;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; &lt;span class="c1"&gt;#130: &amp;#34;azureTunnel/1x1&amp;#34; esp.56cf4304@51.137.113.44 esp.6f49e8d3@95.217.42.98 tun.0@51.137.113.44 tun.0@95.217.42.98 Traffic: ESPin=0B ESPout=0B! ESPmax=0B&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; &lt;span class="c1"&gt;#129: &amp;#34;masterSubnet/0x0&amp;#34;:500 STATE_V2_ESTABLISHED_CHILD_SA (IPsec SA established); EVENT_SA_REKEY in 1544s; newest IPSEC; eroute owner; isakmp#131; idle;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; &lt;span class="c1"&gt;#129: &amp;#34;masterSubnet/0x0&amp;#34; esp.6e81e8da@51.137.113.44 esp.6f72bbc8@95.217.42.98 tun.0@51.137.113.44 tun.0@95.217.42.98 Traffic: ESPin=0B ESPout=0B! ESPmax=0B&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;000&lt;/span&gt; &lt;span class="c1"&gt;#131: &amp;#34;masterSubnet/0x0&amp;#34;:500 STATE_V2_ESTABLISHED_IKE_SA (established IKE SA); EVENT_SA_REKEY in 2121s; newest ISAKMP; idle;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
IPsec specifies properties of connections via &lt;a href="https://en.wikipedia.org/wiki/IPsec#Security_association"&gt;security
associations (SA)&lt;/a&gt;. The parent SA is describes the IKEv2
connections, the child SA is the ESP (encapsulated security
payload) connection.&lt;/p&gt;
&lt;p&gt;
Check IPsec transformation policies&lt;/p&gt;
&lt;div class="src src-sh"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip xfrm policy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Check the state of IPsec transformation policies&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip xfrm state&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Check for dropped packages on the IPsec interface (ipsec1 in our case)&lt;/p&gt;
&lt;div class="src src-text"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip -s link show dev ipsec1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-8" class="outline-2"&gt;
&lt;h2 id="headline-8"&gt;
Additonal Resources
&lt;/h2&gt;
&lt;div id="outline-text-headline-8" class="outline-text-2"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.notnot.ninja/2020/09/19/azure-site-to-site-vpn/"&gt;Build an Azure site-to-site VPN for DevTest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-howto-site-to-site-resource-manager-cli"&gt;Create a virtual network with a Site-to-Site VPN connection using CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libreswan.org/wiki/FAQ#Why_is_it_recommended_to_disable_rp_filter_in_.2Fproc.2Fsys.2Fnet_.3F"&gt;Libreswan: Disable rp_filter for IPsec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libreswan.org/wiki/FAQ#NAT_.2B_IPsec_is_not_working"&gt;Libreswan: NAT and IPsec not working&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libreswan.org/wiki/Subnet_to_subnet_VPN"&gt;Libreswan: Subnet to subnet VPN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Stumbling into Quay: Upgrading from 3.3 to 3.4 with the quay-operator</title><link>https://blog.stderr.at/openshift-platform/quay/2021-09-07-quay-upgrade-3.4/</link><pubDate>Sat, 16 Oct 2021 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/quay/2021-09-07-quay-upgrade-3.4/</guid><description>
&lt;p&gt;
We had the task of answering various questions related to upgrading
Red Hat Quay 3.3 to 3.4 and to 3.5 with the help of the quay-operator.&lt;/p&gt;
&lt;p&gt;
Thankfully (sic!) everything changed in regards to the Quay operator
between Quay 3.3 and Quay 3.4.&lt;/p&gt;
&lt;p&gt;
So this is a brain dump of the things to consider.&lt;/p&gt;
&lt;div id="outline-container-headline-1" class="outline-2"&gt;
&lt;h2 id="headline-1"&gt;
Operator changes
&lt;/h2&gt;
&lt;div id="outline-text-headline-1" class="outline-text-2"&gt;
&lt;p&gt;
With Quay 3.4 the operator was completely reworked and it basically
changed from opinionated to &lt;strong&gt;very&lt;/strong&gt; opinionated. The upgrade works
quite well but you have to be aware about the following points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The name of the custom resource changed from &lt;code&gt;QuayEcosystem&lt;/code&gt; to &lt;code&gt;QuayRegistry&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;configHostname&lt;/code&gt;, used for providing the quay configuration UI, is no longer configurable&lt;/li&gt;
&lt;li&gt;The password for the configuration UI is &lt;strong&gt;always&lt;/strong&gt; regenerated after a configuration re-deployment&lt;/li&gt;
&lt;li&gt;The volume size of the PostgreSQL PVC will change to 50G&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="admonitionblock warning" &gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="icon"&gt;&lt;i class="fa icon-warning" title="warning"&gt;&lt;/i&gt;&lt;/td&gt;&lt;td class="content"&gt;&lt;p&gt;
In my test cluster I was using a 10G Ceph block device and the
StorageClass did not support volume expansion. So my upgrade stopped
at this point and I had to allow volume expansion in the storage
class.&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;A horizontal pod autoscaler is also deploy during the upgrade. The
default is to scale automatically to 20 pods, you might reconsider this…&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With the Quay operator version 3.5 the operator is monitoring all
namespaces for custom resources and needs to be installed in the
openshift-operators namespace, this is how we upgraded Quay to 3.5
including the operator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;change the quay operator channel to 3.5&lt;/li&gt;
&lt;li&gt;trigger an upgrade&lt;/li&gt;
&lt;li&gt;now Quay gets upgraded to version 3.5&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;after the Quay upgrade you need to reinstall the operator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;deinstall the quay operator, Quay is &lt;strong&gt;not&lt;/strong&gt; affected by this&lt;/li&gt;
&lt;li&gt;reinstall the Quay operator (3.5) in all-namespaces&lt;/li&gt;
&lt;li&gt;the re-installation of the operator triggers a quay deployment,
all Quay pods are restarted!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have to manually cleanup old&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;postgres-config-secrets and&lt;/li&gt;
&lt;li&gt;quay-config-bundle&amp;#39;s&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-headline-2" class="outline-2"&gt;
&lt;h2 id="headline-2"&gt;
Backup and restore considerations
&lt;/h2&gt;
&lt;div id="outline-text-headline-2" class="outline-text-2"&gt;
&lt;p&gt;
Red Hat is working on providing documentation on how to backup and
restore Quay in various scenarios. There&amp;#39;s an open task for this
that provides more information
&lt;a href="https://issues.redhat.com/browse/PROJQUAY-2242"&gt;https://issues.redhat.com/browse/PROJQUAY-2242&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Ansible Tower and downloading collections</title><link>https://blog.stderr.at/ansible/2021/07/ansible-tower-and-downloading-collections/</link><pubDate>Sat, 31 Jul 2021 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/ansible/2021/07/ansible-tower-and-downloading-collections/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;Every wondered why Ansible Tower does not start downloading required
collections when you synchronize a project? Here are the stumbling
blocks we discovered so far:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_wrong_name_for_requirements_yml"&gt;Wrong name for requirements.yml&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;When downloading collections Ansible Tower searches for a file
&lt;code&gt;requirements.yml&lt;/code&gt; in the collections directory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Be careful with the file extension: &lt;code&gt;requirements.yml&lt;/code&gt; has to end with
the extension &lt;code&gt;.yml&lt;/code&gt; and &lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_collections_download_is_disabled_in_ansible_tower"&gt;Collections download is disabled in Ansible Tower&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Within Ansible Tower there is a setting called &lt;code&gt;ENABLE COLLECTION(S)
DOWNLOAD&lt;/code&gt; under &lt;code&gt;Settings&lt;/code&gt;/&lt;code&gt;Jobs&lt;/code&gt;. This has to be set to true, which
is also the default.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_no_ansible_galaxy_credential_defined_for_the_organization"&gt;No Ansible Galaxy credential defined for the organization&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Last but not least an Ansible Galaxy credential needs to be defined
for the organization where the project is defined. With the default
installation of Ansible Tower, when the sample playbooks are installed
there is a credential called &lt;code&gt;Ansible Galaxy&lt;/code&gt; defined. You need to assign
this credential to the organization.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If you skip installing the sample playbooks, &lt;strong&gt;no&lt;/strong&gt; &lt;code&gt;Ansible Galaxy&lt;/code&gt;
credential will be defined for you and you have to create it manually.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_how_does_this_actually_work"&gt;How does this actually work?&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Ansible Tower uses a Python virtual environment for running
Ansible. The default environment is installed in
&lt;code&gt;/var/lib/awx/venv/awx&lt;/code&gt;. You can also create custom environments, see
&lt;a href="https://docs.ansible.com/ansible-tower/latest/html/upgrade-migration-guide/virtualenv.html"&gt;Using virtualenv with Ansible Tower&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In the default setup the following files define how collections are downloaded:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;lib/python3.6/site-packages/awx/main/tasks.py&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;lib/python3.6/site-packages/awx/playbooks/project_update.yml&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_task_py"&gt;task.py&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;code&gt;task.py&lt;/code&gt; defines various internal tasks Tower has to run on various
occasions. For example in line number 1930 (Ansible Tower 3.8.3) the
task &lt;code&gt;RunProjectUpdate&lt;/code&gt; gets defined. This is the task Tower
has to run whenever a project update is required.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In our case the function &lt;code&gt;build_extra_vars_file&lt;/code&gt; (line 2083 with
Ansible Tower 3.8.3) defines the variable &lt;code&gt;galaxy_creds_are_defined&lt;/code&gt;
only if the organization has a galaxy credential defined (line 2099
Ansible Tower 3.8.3).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Line 2120 (Ansible Tower 3.8.3) finally defines the Ansible extra
variable &lt;code&gt;collections_enabled&lt;/code&gt; depending on
&lt;code&gt;galaxy_creds_are_defined&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_project_update_yml"&gt;project_update.yml&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So &lt;code&gt;task.py&lt;/code&gt; defines the extra variable &lt;code&gt;collections_enabled&lt;/code&gt; (see
above). Finally the playbook &lt;code&gt;project_update.yml&lt;/code&gt; consumes this extra
variable and only downloads collections if &lt;code&gt;collections_enabled&lt;/code&gt; is
set to &lt;code&gt;true&lt;/code&gt;, see the block string at line 192 (Ansible Tower 3.8.3)
in `project_update.yml.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So long and thanks for all the fish!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Understanding RWO block device handling in OpenShift</title><link>https://blog.stderr.at/openshift-platform/day-2/storage/2021-02-27-understanding-block-devices/</link><pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/day-2/storage/2021-02-27-understanding-block-devices/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;In this blog post we would like to explore OpenShift / Kubernetes
block device handling. We try to answer the following questions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;What happens if multiple pods try to access the same block device?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What happens if we scale a deployment using block devices to more than one replica?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;And finally we want to give a short, high level overview about how the
container storage interface (CSI) actually works.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
A block device provides Read-Write-Once (RWO) storage. This
basically means a local file system mounted by a single node. Do not
confuse this with a cluster (CephFS, GlusterFS) or network file system
(NFS). These file systems provide Read-Write-Many (RWX) storage
mountable on more than one node.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_test_setup"&gt;Test setup&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;For running our tests we need the following resources&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A new namespace/project for running our tests&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A persistent volume claim (PVC) to be mounted in our test pods&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Two pods definitions for mounting the PVC&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_step_1_creating_a_new_namespaceproject"&gt;Step 1: Creating a new namespace/project&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To run our test cases we created a new project with OpenShift&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc new-project blockdevices&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_step_2_defining_a_block_pvc"&gt;Step 2: Defining a block PVC&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Our cluster is running the rook operator (&lt;a href="https://rook.io" class="bare"&gt;https://rook.io&lt;/a&gt;) and provides a ceph-block
storage class for creating block devices:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ oc get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate false 4d14h&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s take a look a the details of the storage class:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;$ oc get sc -o yaml ceph-block
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ceph-block
parameters:
clusterID: rook-ceph
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
csi.storage.k8s.io/fstype: ext4 &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
imageFeatures: layering
imageFormat: &amp;#34;2&amp;#34;
pool: blockpool
provisioner: rook-ceph.rbd.csi.ceph.com
reclaimPolicy: Delete
volumeBindingMode: Immediate&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;So whenever we create a PVC using this storage class the Ceph
provisioner will also create an EXT4 file system on the block device.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To test block device handling we create the following persistent volume claim (PVC):&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: block-claim
spec:
accessModes:
- ReadWriteOnce &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
resources:
requests:
storage: 1Gi
storageClassName: ceph-block&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;The access mode is set to ReadWriteOnce (RWO), as block devices&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc create -f pvc.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ oc get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
block-claim Bound pvc-bd68be5d-c312-4c31-86a8-63a0c22de844 1Gi RWO ceph-block 91s&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To test our shiny new block device we are going to use the following three pod definitions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="title"&gt;block-pod-a&lt;/div&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: v1
kind: Pod
metadata:
labels:
run: block-pod-a
name: block-pod-a
spec:
containers:
- image: registry.redhat.io/ubi8/ubi:8.3
name: block-pod-a
command:
- sh
- -c
- &amp;#39;df -h /block &amp;amp;&amp;amp; findmnt /block &amp;amp;&amp;amp; sleep infinity&amp;#39;
volumeMounts:
- name: blockdevice
mountPath: /block
volumes:
- name: blockdevice
persistentVolumeClaim:
claimName: block-claim&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="title"&gt;block-pod-b&lt;/div&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: v1
kind: Pod
metadata:
labels:
run: block-pod-b
name: block-pod-b
spec:
affinity:
podAntiAffinity: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: run
operator: In
values:
- block-pod-a
topologyKey: kubernetes.io/hostname
containers:
- image: registry.redhat.io/ubi8/ubi:8.3
name: block-pod-b
command:
- sh
- -c
- &amp;#39;df -h /block &amp;amp;&amp;amp; findmnt /block &amp;amp;&amp;amp; sleep infinity&amp;#39;
volumeMounts:
- name: blockdevice
mountPath: /block
volumes:
- name: blockdevice
persistentVolumeClaim:
claimName: block-claim&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We use an &lt;em&gt;AntiAffinity&lt;/em&gt; rule for making sure that &lt;em&gt;block-pod-b&lt;/em&gt; runs
on a &lt;strong&gt;different&lt;/strong&gt; node than &lt;em&gt;block-pod-a&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="title"&gt;block-pod-c&lt;/div&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;apiVersion: v1
kind: Pod
metadata:
labels:
run: block-pod-c
name: block-pod-c
spec:
affinity:
podAffinity: &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: run
operator: In
values:
- block-pod-a
topologyKey: kubernetes.io/hostname
containers:
- image: registry.redhat.io/ubi8/ubi:8.3
name: block-pod-c
command:
- sh
- -c
- &amp;#39;df -h /block &amp;amp;&amp;amp; findmnt /block &amp;amp;&amp;amp; sleep infinity&amp;#39;
volumeMounts:
- name: blockdevice
mountPath: /block
volumes:
- name: blockdevice
persistentVolumeClaim:
claimName: block-claim&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;We use an &lt;em&gt;Affinity&lt;/em&gt; rule for making sure that &lt;em&gt;block-pod-c&lt;/em&gt; runs
on the &lt;strong&gt;same&lt;/strong&gt; node as &lt;em&gt;block-pod-a&lt;/em&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In our first test we want to make sure that both pods are running on
separate cluster nodes. So we create &lt;em&gt;block-pod-a&lt;/em&gt; and &lt;em&gt;block-pod-b&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ oc create -f block-pod-a.yml
$ oc create -f block-pod-b.yml&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;After a few seconds we can check the state of our pods:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ oc get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
block-pod-a 1/1 Running 0 46s 10.130.6.4 infra02.lan.stderr.at &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
block-pod-b 0/1 ContainerCreating 0 16s &amp;lt;none&amp;gt; infra01 &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Hm, block-pod-b is in the state &lt;em&gt;ContainerCreating&lt;/em&gt;, let’s check the
events. Also note that it is running on another node (infra01) then
&lt;em&gt;block-pod-a&lt;/em&gt; (infra02).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;10s Warning FailedAttachVolume pod/block-pod-b Multi-Attach error for volume &amp;#34;pvc-bd68be5d-c312-4c31-86a8-63a0c22de844&amp;#34; Volume is already used by pod(s) block-pod-a&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Ah, so because of our block device with RWO access mode and
&lt;em&gt;block-pod-b&lt;/em&gt; running on separate cluster node, OpenShift or K8s can’t
attach the volume to our &lt;em&gt;block-pod-b&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;But let’s try another test and let’s create a third pod &lt;em&gt;block-pod-c&lt;/em&gt;
that should run on the same node as &lt;em&gt;block-pod-a&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ oc create -f block-pod-c.yml&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Now let’s check the status of &lt;em&gt;block-pod-c&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ oc get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
block-pod-a 1/1 Running 0 6m49s 10.130.6.4 infra02.lan.stderr.at &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
block-pod-b 0/1 ContainerCreating 0 6m19s &amp;lt;none&amp;gt; infra01 &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
block-pod-c 1/1 Running 0 14s 10.130.6.5 infra02.lan.stderr.at &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Oh, &lt;em&gt;block-pod-c&lt;/em&gt; is running on node &lt;em&gt;infra02&lt;/em&gt; and mounted the RWO volume. Let’s check the events for &lt;em&gt;block-pod-c&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;3m6s Normal Scheduled pod/block-pod-c Successfully assigned blockdevices/block-pod-c to infra02.lan.stderr.at
2m54s Normal AddedInterface pod/block-pod-c Add eth0 [10.130.6.5/23]
2m54s Normal Pulled pod/block-pod-c Container image &amp;#34;registry.redhat.io/ubi8/ubi:8.3&amp;#34; already present on machine
2m54s Normal Created pod/block-pod-c Created container block-pod-c
2m54s Normal Started pod/block-pod-c Started container block-pod-c&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;When we compare this with the events for &lt;em&gt;block-pod-a&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;9m41s Normal Scheduled pod/block-pod-a Successfully assigned blockdevices/block-pod-a to infra02.lan.stderr.at
9m41s Normal SuccessfulAttachVolume pod/block-pod-a AttachVolume.Attach succeeded for volume &amp;#34;pvc-bd68be5d-c312-4c31-86a8-63a0c22de844&amp;#34;
9m34s Normal AddedInterface pod/block-pod-a Add eth0 [10.130.6.4/23]
9m34s Normal Pulled pod/block-pod-a Container image &amp;#34;registry.access.redhat.com/ubi8/ubi:8.3&amp;#34; already present on machine
9m34s Normal Created pod/block-pod-a Created container block-pod-a
9m34s Normal Started pod/block-pod-a Started container block-pod-a&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So the &lt;em&gt;AttachVolume.Attach&lt;/em&gt; message is missing in the events for
&lt;em&gt;block-pod-c&lt;/em&gt;. Because the volume is already attached to the node,
interesting.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Even with RWO block device volumes it is possible to use the
same volume in multiple pods &lt;strong&gt;if&lt;/strong&gt; the pods a running on the &lt;strong&gt;same&lt;/strong&gt; node.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;I was not aware of this possibility and always had the believe with an
RWO block device only one pod can access the volume. That’s the
problem with believing :-)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Thanks or reading this far.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Basic usage of git</title><link>https://blog.stderr.at/integrations/general/2020-05-08-git-and-github-basics/</link><pubDate>Fri, 08 May 2020 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/integrations/general/2020-05-08-git-and-github-basics/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;This is a very short and hopefully simple introduction on how to use
&lt;a href="https://git-scm.com/"&gt;Git&lt;/a&gt; when you would like to contribute to
projects hosted on &lt;a href="http://github.com"&gt;github.com&lt;/a&gt;. The same workflow should also work for
projects on &lt;a href="http://gitlab.com"&gt;gitlab.com&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_introduction"&gt;Introduction&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;There is this fancy mega application hosted on github called
&lt;a href="https://github.com/rhatservices/megaapp"&gt;megaapp&lt;/a&gt; that you would like
to contribute to. It’s perfect but there’s just this little feature
missing to make it even more perfect.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This is how we would tackle this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock warning"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-warning" title="Warning"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
rocket science ahead
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_glossary"&gt;Glossary&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;table class="tableblock frame-all grid-all stretch"&gt;
&lt;colgroup&gt;
&lt;col style="width: 27.2727%;"/&gt;
&lt;col style="width: 72.7273%;"/&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th class="tableblock halign-left valign-top"&gt;Term&lt;/th&gt;
&lt;th class="tableblock halign-left valign-top"&gt;Definition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;fork&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;A (personal) copy of a repository you created on github or gitlab.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;upstream&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;When creating forks of repositories on github or gitlab, the original repository hosting the project&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;index&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;The staging area git uses before you can commit to a repository&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;remote repository&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;A repository hosted on a server shared by developers&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;local repository&lt;/p&gt;&lt;/td&gt;
&lt;td class="tableblock halign-left valign-top"&gt;&lt;p class="tableblock"&gt;A local copy of a repository stored on you machine.&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_step_1_fork_the_repository_on_github_com"&gt;Step 1: Fork the repository on github.com&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Login to you Github account and navigate to the project you would like
to fork, &lt;a href="https://github.com/rhatservices/megaapp"&gt;megaapp&lt;/a&gt; in our
example.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Click on the the fork button, as depicted in the image below:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/integrations/general/images/fork.png" alt="fork"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If you are a member of several projects on github.com, github is going
to ask you into which project you would like to clone this repository.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;After selecting the project or your personal account, github is going
to clone the repository into the project you selected. For this
example I’m going to use my personal github account &amp;#34;tosmi&amp;#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_step_2_clone_the_repository_to_you_workstation"&gt;Step 2: Clone the repository to you workstation&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Next we are going to clone our fork from &lt;a href="#_step_1_fork_the_repository_on_github_com"&gt;Step 1: Fork the repository on github.com&lt;/a&gt; to our workstation and start working on the new
feature.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;After forking the upstream project you are redirect to your personal
copy of the project. Click on the &amp;#34;Clone or download&amp;#34; button and
select the link. You can choose between SSH and HTTPS protocols for
downloading the project. We are going to use SSH.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/integrations/general/images/clone.png" alt="clone"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Copy the link into a terminal and execute the &lt;em&gt;git clone&lt;/em&gt; command:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git clone git@github.com:tosmi/megaapp.git&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_step_3_create_a_feature_branch_for_your_new_fancy_feature"&gt;Step 3: Create a feature branch for your new fancy feature&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Change into the directory of the project you downloaded in &lt;a href="#_step_2_clone_the_repository_to_you_workstation"&gt;Step 2: Clone the repository to you workstation&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;cd megaapp&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Now we create a feature branch with a short name that describes our new feature:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;git checkout -b tosmi/addoption&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Because we would like to add a new option to &lt;em&gt;megaapp&lt;/em&gt; we call this feature branch &lt;em&gt;addoption&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We are also prefixing the feature branch with our github username so that
it is clear for the upstream project maintainer(s) who is contributing this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;How you name you branches is opinionated, so we would search for
upstream project guidelines and if there are none maybe look at some
existing pull request how other people are naming there branches. If we
find no clue upstream we sticking with &lt;em&gt;&amp;lt;github username&amp;gt;/&amp;lt;branch
name&amp;gt;&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We can now start adding our mega feature to the project.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_step_4_add_you_changes_to_the_git_index"&gt;Step 4: Add you changes to the Git index&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Before we can commit our changes, we have to place the changes made in
the so called &lt;em&gt;index&lt;/em&gt; or staging area:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git add &amp;lt;path to file you have changed&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If we would like to place all of our changes onto the index we could execute&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git add -A&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_step_5_commit_your_changes"&gt;Step 5: Commit your changes&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;After adding our changes to the Git index we can commit with&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git commit&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This will open our favorite editor and we can type a commit
message. The first line should be a short description of our change,
probably not longer than 70 to 80 characters. After two newlines we
can enter a detailed explanation of your changes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This is an example commit message&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;Added a `version` option to output the current version of megaapp
This change introduces a `version` option to megaapp. The purpose is
to output the current version of megaapp for users. This might be
helpful when users open a bug report so we can see what version is
affected.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;After saving the message and we have successfully created a commit.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Remember this is now only stored in the local copy of the
repository! We still have to push our changes to github.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;There is also the option to add the commit comment directly on the command line&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git commit -m &amp;#39;Added a `version` option to output the current version of megaapp
This change introduces a `version` option to megaapp. The purpose is
to output the current version of megaapp for users. This might be
helpful when users open a bug report so we can see what version is
affected.&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_step_6_pushing_our_local_changes_to_our_forked_repo_on_github_com"&gt;Step 6: Pushing our local changes to our forked repo on github.com&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We execute&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git push&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;to push our local changes to the forked repository hosted on github.com.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_step_7_creating_a_pull_request_on_github_com"&gt;Step 7: Creating a pull request on github.com&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We navigate to our personal project page of the forked repository on
github. For the fork we are using in this example this is
&lt;a href="http://github.com/tosmi/megaapp" class="bare"&gt;http://github.com/tosmi/megaapp&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Github is going to show us a button &amp;#34;Compare &amp;amp; pull request&amp;#34;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/integrations/general/images/pull_request.png" alt="pull request"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;After clicking on that button we are able to review the changes we
would like to include in this pull request.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If we are happy with our changes we click on &amp;#34;Create pull
request&amp;#34;. The upstream owner of the repository will get notified and
we can see our open pull request on the upstream project page under
&amp;#34;Pull requests&amp;#34;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If there are CI test configured for that project they will start to
run and we can see if our pull request is going to pass all test
configured.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_rebasing_to_current_upstream_if_required"&gt;Rebasing to current upstream if required&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Sometimes a upstream project maintainer asks you to rebase your work
on the current upstream master branch. The following steps explain the
basic workflow.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;First we are going to create a new remote location of our repository
called &lt;em&gt;upstream&lt;/em&gt;. &lt;em&gt;Upstream&lt;/em&gt; points to the upstream project
repository. We will not push to this location, in most cases this is
not possible because you do not have write access to a remote upstream
repository. It is just used for pulling upstream changes in our forked
repository.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Execute the following commands to add the upstream repository as a new
remote location and display all remote locations currently defined.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git remote add upstream https://github.com/rhatservices/megaapp.git
$ git remote -v origin
git@github.com:tosmi/megaapp.git (fetch) origin
git@github.com:tosmi/megaapp.git (push) upstream
https://github.com/rhatservices/megaapp.git (fetch) upstream
https://github.com/rhatservices/megaapp.git (push)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;As we hopefully implemented our new feature in feature branch, we can
pull changes from the upstream master branch into our local copy of
the master branch. Remember we are using a feature branch and master
should be kept clean from local changes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git checkout master
Switched to branch &amp;#39;master&amp;#39;
Your branch is up to date with &amp;#39;origin/master&amp;#39;.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So now we have this older copy of the upstream master branch checked
out and we would like to update it to the latest and greatest from the
upstream master branch.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git pull upstream master
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 2), reused 6 (delta 2), pack-reused 0
Unpacking objects: 100% (6/6), 630 bytes | 157.00 KiB/s, done.
From https://github.com/rhatservices/megaapp
* branch master -&amp;gt; FETCH_HEAD
* [new branch] master -&amp;gt; upstream/master
Updating 4d8584e..ddfd077
Fast-forward
cmd/megaapp/main.go | 2 ++
cmd/megaapp/rule.go | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+)
create mode 100644 cmd/megaapp/rule.go&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;With the pull command above you pulled all changes from the upstream
master branch into you local copy of master. Just to be sure let’s
display all available branches, local and remote ones.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Branches with a name &lt;em&gt;remote/&amp;lt;remote name&amp;gt;/&amp;lt;branch name&amp;gt;&lt;/em&gt; are remote
branches that git knows about. &lt;em&gt;Origin&lt;/em&gt; points to our forked
repository and is also the default location for push operations.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git branch -a
master
* tosmi/megafeature
remotes/origin/HEAD -&amp;gt; origin/master
remotes/origin/master
remotes/origin/tosmi/megafeature
remotes/upstream/master&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So finally to &lt;strong&gt;rebase&lt;/strong&gt; our feature branch to the upstream master
branch we first need to checkout our feature branch via&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git checkout tosmi/megafeature&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Now we are able to rebase our changes to upstream master. Git
basically pulls in all changes from the master branch and re-applies
the changes we did in our feature branch.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;git rebase upstream/master
Successfully rebased and updated refs/heads/tosmi/megafeature.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;There might be merge conflicts when git tries to apply you changes
from your feature branch. You have to fix those changes, &lt;em&gt;git add&lt;/em&gt; the
fixed files and execute &lt;em&gt;git rebase continue&lt;/em&gt;. Luckily this is not the
case for your megafeature.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;As we have successfully rebased our feature branch to upstream master
we can now try to push changes made to our forked github repository.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git push
To github.com:tosmi/megaapp.git
! [rejected] tosmi/megafeature -&amp;gt; tosmi/megafeature (non-fast-forward)
error: failed to push some refs to &amp;#39;git@github.com:tosmi/megaapp.git&amp;#39;
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: &amp;#39;git pull ...&amp;#39;) before pushing again.
hint: See the &amp;#39;Note about fast-forwards&amp;#39; in &amp;#39;git push --help&amp;#39; for details.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Oh, this fails of course! The reason is that our local feature branch
and the remote feature branch have a different commit history. The
remote feature branch is missing the commits from master that we
applied when rebasing on the current master branch.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So let’s try again, this time using the &lt;em&gt;--force-with-lease&lt;/em&gt;
option. You could also use &lt;em&gt;-f&lt;/em&gt; or &lt;em&gt;--force&lt;/em&gt; but &lt;em&gt;--force-with-lease&lt;/em&gt;
will stop you if someone else (our you) has modified the remote feature
branch meanwhile. If you push with &lt;em&gt;-f&lt;/em&gt; or &lt;em&gt;--force&lt;/em&gt; anyways you might loose changes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git push --force-with-lease
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 295 bytes | 295.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:tosmi/megaapp.git
+ acf66a3...39357b2 tosmi/megafeature -&amp;gt; tosmi/megafeature (forced update)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;But as no one modified the remote feature branch while we did our
rebase the force push goes through.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Our merge request (if we opened one already) is now updated to the
latest upstream master branch and merging our feature should be a
breeze. You might notify the upstream project maintainer that you
feature branch is up to date and ready for merging&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_using_gits_interactive_rebase_to_change_you_commit_history"&gt;Using git’s interactive rebase to change you commit history&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;When working with upstream projects it might be that a project
maintainer requests that you rework your git history before he is
willing to merge your changes. For example this could be that case if
you have plenty of commits with very small changes (e.g. fixed typos).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The general rule is that one commit should implement one change. This
is not a hard rule, but usually works.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Let’s look at an example. For the implementation of our new feature
that we would like to bring upstream we have the following commit history&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git log --oneline
0a5221d (HEAD -&amp;gt; tosmi/megafeature) fixed typo
0e60d12 update README
bf2ef3c update&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We have updated README.md in the repository but there a three commits
for this little change. Before bringing this upstream in our pull
request, we would like to convert those three commits into a single
one and also make the commit message a little more meaningful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We execute the following command to start reworking our commit history&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git rebase -i&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Git will drop us into our beloved editor (vi in this case), under
Linux you could change the editor git uses by modifying the $EDITOR
environment variable. We are going to see the following output:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;pick bf2ef3c update
pick 0e60d12 update README
pick 0a5221d fixed typo
# Rebase 39357b2..0a5221d onto 39357b2 (3 commands)
#
# Commands:
# p, pick &amp;lt;commit&amp;gt; = use commit
# r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message
# e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending
# s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit
# f, fixup &amp;lt;commit&amp;gt; = like &amp;#34;squash&amp;#34;, but discard this commit&amp;#39;s log message
# x, exec &amp;lt;command&amp;gt; = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with &amp;#39;git rebase --continue&amp;#39;)
# d, drop &amp;lt;commit&amp;gt; = remove commit
# l, label &amp;lt;label&amp;gt; = label current HEAD with a name
# t, reset &amp;lt;label&amp;gt; = reset HEAD to a label
# m, merge [-C &amp;lt;commit&amp;gt; | -c &amp;lt;commit&amp;gt;] &amp;lt;label&amp;gt; [# &amp;lt;oneline&amp;gt;]
# . create a merge commit using the original merge commit&amp;#39;s
# . message (or the oneline, if no original merge commit was
# . specified). Use -c &amp;lt;commit&amp;gt; to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Git automatically selected commit id bf2ef3c as the basis for our
rebase. We could also have specified the commit id where we would like
to start our rebase operation e.g.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;git rebase -i bf2ef3c&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In our editor of choice we can now tell git what it should do with the selected commits.
Please go ahead and read the helpfull explanation text in comments (prefixed with &amp;#39;#&amp;#39;)
to get a better understanding of the operations supported.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In our case we would like to &lt;em&gt;squash&lt;/em&gt; the last commits. So we change the lines with &lt;em&gt;pick&lt;/em&gt; to
&lt;em&gt;squash&lt;/em&gt; until it looks like the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;pick bf2ef3c update
squash 0e60d12 update README
squash 0a5221d fixed typo&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We would like to squash commits 0a5221d and 0e60d12 onto commit
bf2ef3c. Keep in mind that git actually reverses the order of
commits. So 0a5221d is the last commit we added.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If we save the file and quit our editor (I’m using vi here), git drops us into
another buffer where we can finally modify the commits&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt; This is a combination of 3 commits.
# This is the 1st commit message:
update
# This is the commit message #2:
update README
# This is the commit message #3:
fixed typo
# Please enter the commit message for your changes. Lines starting
# with &amp;#39;#&amp;#39; will be ignored, and an empty message aborts the commit.
#
# Date: Mon May 18 15:46:37 2020 +0200
#
# interactive rebase in progress; onto 39357b2
# Last commands done (3 commands done):
# squash 0e60d12 update README
# squash 0a5221d fixed typo
# No commands remaining.
# You are currently rebasing branch &amp;#39;tosmi/megafeature&amp;#39; on &amp;#39;39357b2&amp;#39;.
#
# Changes to be committed:
# modified: README.md
#&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We can see all three commit message and we are going to modify those messages until we are happy&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;# This is a combination of 3 commits.
# This is the 1st commit message:
updated README.md to megafeature
as we added megafeature, it makes sense to include a short note about it also in README.md
# Please enter the commit message for your changes. Lines starting
# with &amp;#39;#&amp;#39; will be ignored, and an empty message aborts the commit.
#
# Date: Mon May 18 15:46:37 2020 +0200
#
# interactive rebase in progress; onto 39357b2
# Last commands done (3 commands done):
# squash 0e60d12 update README
# squash 0a5221d fixed typo
# No commands remaining.
# You are currently rebasing branch &amp;#39;tosmi/megafeature&amp;#39; on &amp;#39;39357b2&amp;#39;.
#
# Changes to be committed:
# modified: README.md
#&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;When we are happy with new commit message we just save and quit our
editor. Git will now rewirte the history and when we take look at the
commit history again we will see our changes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;$ git log --oneline
91d1ae2 (HEAD -&amp;gt; tosmi/megafeature) updated README.md to megafeature
39357b2 (origin/tosmi/megafeature) added a mega feature
ddfd077 (upstream/master, master) added rule command
4d8584e (origin/master, origin/HEAD) Update README.md
eb6ccbc Create README.md
60fcabc start using cobra for argument parsing
5140ed0 import .gitignore
d2b55d1 import a simple Makefile
2ecb412 initial import&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;We only have commit 91d1ae2 now , which includes all three changes from
the commits before.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock warning"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-warning" title="Warning"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Rewriting the history of a repository is a dangerous
operation. Especially when you are working in a team. It is not
advised to change the history of commits that got already pushed to a
remote location. Otherwise your teammates will get confused next time
they try to push or pull from the shared repository.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So it’s OK to change the commit history of a feature branch that only
you are using, but be careful when working on branches more than one
developer is using.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Red Hat Satellite Cheat Sheet</title><link>https://blog.stderr.at/integrations/general/2020-04-15-satellite-cheatsheet/</link><pubDate>Wed, 15 Apr 2020 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/integrations/general/2020-04-15-satellite-cheatsheet/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;Cheat sheet for various Red Hat Satellite tasks from a newbie to a newbie.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_requirements"&gt;Requirements&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;up to Satellite 6.7 RHEL 7.X&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;4 CPU Cores&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;20 GB of RAM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;300 GB disk space&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;for more info see the &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_satellite/6.6/html/installing_satellite_server_from_a_connected_network/preparing_your_environment_for_installation#storage_requirements"&gt;prerequistes guide&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_installation"&gt;Installation&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Satellite up to version 6.7 uses puppet for installation. You can use&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;puppet filebucket&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;to restore files modified by puppet.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Satellite requires the &lt;em&gt;Red Hat Satellite Infrastructure Subscription&lt;/em&gt;, check if it’s available with&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;subscription-manager list --all --available --matches &amp;#39;Red Hat Satellite Infrastructure Subscription&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If not attach it with&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;subscription-manager attach --pool=pool_id&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Next disable all repos and enable only supported repostories via&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;subscription-manager repos --disable &amp;#34;*&amp;#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;and enable required repositories&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;subscription-manager repos --enable=rhel-7-server-rpms \
--enable=rhel-7-server-satellite-6.6-rpms \
--enable=rhel-7-server-satellite-maintenance-6-rpms \
--enable=rhel-server-rhscl-7-rpms \
--enable=rhel-7-server-ansible-2.8-rpms&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;then clean cached all repo data via&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt; yum clean all&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;and install satellite packages via&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;yum install satellite&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Install satellite with&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;satellite-installer --scenario satellite \
--foreman-initial-organization &amp;#34;initial_organization_name&amp;#34; \
--foreman-initial-location &amp;#34;initial_location_name&amp;#34; \
--foreman-initial-admin-username admin_user_name \
--foreman-initial-admin-password admin_password&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_backup_restore_cloning"&gt;Backup / Restore / Cloning&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Use &lt;code&gt;satellite-maintain&lt;/code&gt; for doing offline and online backups&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;satellite-maintain backup offline /backup/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;when using the &lt;em&gt;online&lt;/em&gt; option make sure that no new content view or
content view versions should be created while the backup is
running. basically satellite should be idle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_cloning_satellite"&gt;Cloning Satellite&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The online/offline options also backup &lt;em&gt;/var/lib/pulp&lt;/em&gt;, which contains
all downloaded packages. This could be &lt;strong&gt;huge&lt;/strong&gt;. There’s an option to skip this so&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;satellite-maintain backup offline --skip-pulp-tar /backup/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
For a restore you always need the content of &lt;em&gt;/var/lib/pulp&lt;/em&gt;.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This is mainly usefull for cloning satellite. You backup everything
except &lt;em&gt;/var/lib/pulp&lt;/em&gt;, copy the backup to a second system and rsync
&lt;em&gt;/var/lib/pulp&lt;/em&gt; to the new system. Then restore the backup and
satellite should work as normal on the clone.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_snaphot_backups"&gt;Snaphot backups&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Satellite also supports backups via LVM snapshots. For more information see &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_satellite/6.6/html/administering_red_hat_satellite/chap-red_hat_satellite-administering_red_hat_satellite-backup_and_disaster_recovery#snapshot-backup_assembly"&gt;Snapshot backup&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_upgrades"&gt;Upgrades&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="olist arabic"&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;
&lt;p&gt;Read the Satellite release notes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Do a offline backup see &lt;a href="#Backup / Restore"&gt;[Backup / Restore]&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You could clone satellite to a other system&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If there are local changes to dhcpd or dns configurations use&lt;/p&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;satellite-installer --foreman-proxy-dns-managed=false --foreman-proxy-dhcp-managed=false&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;to stop satellite-install from overwriting those files.&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;install the latest version of satellite-maintain via&lt;/p&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;yum install rubygem-foreman_maintain&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;check for available satellite versions with&lt;/p&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;satellite-maintain upgrade list-versions&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;test the possible upgrade with&lt;/p&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;satellite-maintain upgrade check --target-version 6.7&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and finally run the upgrade and PRAY!&lt;/p&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;satellite-maintain upgrade run --target-version 6.7&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_various_tips_and_tricks"&gt;Various tips and tricks&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_installing_packages_via_yum"&gt;Installing packages via yum&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Satellite installs a yum plugin called &lt;code&gt;foreman-protector&lt;/code&gt;. If you try
to install a package via yum you get the following message&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-none hljs"&gt;WARNING: Excluding 12190 packages due to foreman-protector.
Use foreman-maintain packages install/update &amp;lt;package&amp;gt;
to safely install packages without restrictions.
Use foreman-maintain upgrade run for full upgrade.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;so use&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;satellite-maintain install &amp;lt;package name&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_os_package_upgrade"&gt;OS package upgrade&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This should be done via satellite-maintain because all packages are locked by default (see &lt;a href="#_installing_packages_via_yum"&gt;Installing packages via yum&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This basically comes down to running&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oreman-maintain upgrade run --target-version 6.6.z&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;for upgrading OS packages if you have satellite 6.6 installed.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Helpful oc / kubectl commands</title><link>https://blog.stderr.at/openshift-platform/day-2/fundamentals/2020-04-01-oc-commands/</link><pubDate>Wed, 01 Apr 2020 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/day-2/fundamentals/2020-04-01-oc-commands/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;This is a list of useful oc and/or kubectl commands so they won’t be forgotton. No this is not a joke…​&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_list_all_pods_in_state_running"&gt;List all pods in state &lt;em&gt;Running&lt;/em&gt;&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc get pods --field-selector=status.phase=Running&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_list_all_pods_in_state_running_and_show_there_resource_usage"&gt;List all pods in state &lt;em&gt;Running&lt;/em&gt; and show there resource usage&lt;/h3&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc get pods --field-selector=status.phase=Running -o json|jq &amp;#34;.items[] | {name: .metada
ta.name, res: .spec.containers[].resources}&amp;#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_list_events_sort_by_time_created"&gt;List events sort by time created&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt; oc get events --sort-by=&amp;#39;.lastTimestamp&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_explain_objects_while_specifing_the_api_version"&gt;Explain objects while specifing the api version&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Sometimes when you run &lt;code&gt;oc explain&lt;/code&gt; you get a message in DESCRIPTION that this particular version is deprecated, e.g. you are running &lt;code&gt;oc explain deployment&lt;/code&gt; and get&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;DESCRIPTION:
DEPRECATED - This group version of Deployment is deprecated by
apps/v1/Deployment. See the release notes for more information. Deployment
enables declarative updates for Pods and ReplicaSets.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
Note the DEPRECTATED message above
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;if you want to see the documentation for the object that has not been deprecated you can use&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc explain deployment --api-version=apps/v1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_magic_with_oc_set"&gt;Magic with oc set&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;&lt;code&gt;oc set&lt;/code&gt; is actually a very versatile command. Studying &lt;code&gt;oc set -h&lt;/code&gt; is a good idea, here are some examples&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_set_route_weights_when_alternatebackends_in_a_route_are_defined"&gt;Set route weights when alternateBackends in a route are defined&lt;/h3&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc set route-backends bluegreen blue=1 green=9&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_set_resources_on_the_command_line"&gt;Set resources on the command line&lt;/h3&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc set resources dc cakephp-mysql-example --limits=memory=1Gi,cpu=200m&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item></channel></rss>