Programming

basic programming

Deploy and Use SealedSecret and KubeSeal on Openshift 4.x

Sealed Secrets are a way to encrypt Kubernetes Secrets value that can be created by anyone, but can only be decrypted by the controller running in the target cluster recovering the original object. This is a good way if we want to store our sensitive configuration values into a git repository, especially when doing a gitops approach.

First is we need to install helm and add sealed-secret repo to it,

$ brew install helm

$ helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets

Next is we need to create a specific Namespace and install our sealed-secret there,

$ oc project sealed-secrets

$ helm install my-sealed-secret  \
         --set containerSecurityContext.enabled=false \
		 --set podSecurityContext.enabled=false \
		 sealed-secrets/sealed-secrets	

Lets try to create a simple Kubernetes secret

$ oc create secret generic app-cred-secret \
		--from-literal=username=username123 \ 
		--from-literal=password=password123 \ 
		--dry-run=client -n edwin-ns -o yaml  > secret.yaml

Where the result would be like this,

apiVersion: v1
data:
  password: cGFzc3dvcmQxMjM=
  username: dXNlcm5hbWUxMjM=
kind: Secret
metadata:
  creationTimestamp: null
  name: app-cred-secret
  namespace: edwin-ns

Now lets try to use Kubeseal to generate a secret which is being encrypted. We can specify “controller-name” based on generated service name within “sealed-secrets” namespace.

$ brew install kubeseal

$ kubeseal --controller-name=my-sealed-secret-sealed-secrets \
       --controller-namespace=sealed-secrets -o yaml < secret.yaml > secret.sealed.yaml

We can see the result of the encrypted yaml,

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: app-cred-secret
  namespace: edwin-ns
spec:
  encryptedData:
    password: AgBXkADvKsjAHS31UwWFT+........eJtODYDQw==
    username: AgAP40ssm84PhmNYDKPfDf/Cf......JDBQDtQ==
  template:
    metadata:
      creationTimestamp: null
      name: app-cred-secret
      namespace: edwin-ns

After that, we can implement it directly using “oc apply” command

$ oc apply -f secret.sealed.yaml -n edwin-ns

and we can validate by running below command,

$ oc get sealedsecrets

NAME               AGE
app-cred-secret    53m

We can see that our secret is succesfully created in our namespace

$ oc get secret app-cred-secret -n edwin-ns

NAME              TYPE     DATA   AGE
app-cred-secret   Opaque   2      55m

Deploying a Dot Net Core Apps into Openshift 4

The goal of this article is to display a simple hello-world apps build on top of a .net core 7 that can be use to test a deployment to Openshift 4 platform. And we can start it by using a git clone command

$ git clone https://github.com/edwin/hello-world-dot-net-core

Go to the corresponding folder,

$ cd hello-world-dot-net-core

Create a namespace for this app,

$ oc new-project dot-net-ns

And run this command within the sourcecode folder,

$ oc new-app dotnet:7.0-ubi8~.

It will generate logs like this,

warning: Cannot check if git requires authentication.
--> Found image 4466483 (2 months old) in image stream "openshift/dotnet" under tag "7.0-ubi8" for "dotnet:7.0-ubi8"

    .NET 7
    ------
    Platform for building and running .NET 7 applications

    Tags: builder, .net, dotnet, dotnetcore, dotnet-70

    * A source build using source code from https://github.com/edwin/hello-world-dot-net-core#master will be created
      * The resulting image will be pushed to image stream tag "hello-world-dot-net-core:latest"
      * Use 'oc start-build' to trigger a new build

--> Creating resources ...
    imagestream.image.openshift.io "hello-world-dot-net-core" created
    buildconfig.build.openshift.io "hello-world-dot-net-core" created
    deployment.apps "hello-world-dot-net-core" created
    service "hello-world-dot-net-core" created
--> Success
    Build scheduled, use 'oc logs -f buildconfig/hello-world-dot-net-core' to track its progress.
    Application is not exposed. You can expose services to the outside world by executing one or more of the commands below:
     'oc expose service/hello-world-dot-net-core'
    Run 'oc status' to view your app.

And finally we can create a route for this service,

$ oc create route edge --service=hello-world-dot-net-core

We can try to do some changes on Index.cshtml file,

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://redhat.com">Red Hat loves dotnet</a>.</p>
</div>

Save and redeploy it by running below command in the root sourcecode folder,

$ oc start-build hello-world-dot-net-core --from-dir=.

The result would be something like this,

Lets do some more changes, and deploy it to Openshift

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://redhat.com">Red Hat loves alot of programming language but we loves dotnet more</a>.</p>
</div>

And we instantly can see changes within the web page,

Code can be seen here,

https://github.com/edwin/hello-world-dot-net-core

How to Expose Openshift Route into a Secure Endpoint

We can do below command to expose a specific Openshift Service into a route or URL

$ oc expose svc <service-name>

but it would create a regular not-secure http endpoint, which sometimes not sufficient enough to fulfil our requirements. Therefore we need to find a way to create a secure route endpoint, and we can achieve that condition by using below command

$ oc create route edge --service <service-name>

It would create a route with an edge TLS termination.

Using Settings.xml to handle Multiple Mirrors in Maven

The goal of having an internal artifactory is to host library for maven, so everytime we do java build, we dont need to pull the whole libraries from internet. Usally we have something like Nexus or JFrog for this.

But the thing is, sometimes we already have a working application that is running well when pulling libraries from online before, and now we need to change it into pointing into our artifact repository without have to change the maven’s pom.xml configuration.

for example, we have some pom.xml file which is pointing to a specific online repository like the sample below,

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.4</version>
		<relativePath /> 
	</parent>
	<groupId>com.something</groupId>
	<artifactId>some-java-app</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>some-java-app</name>
	<description>some java app</description>
	<properties>
		<java.version>17</java.version>
		<tomcat.version>9.0.68</tomcat.version>
	</properties>
	<repositories>
		<repository>
			<id>splunk-releases</id>
			<name>Splunk Releases</name>
			<url>https://splunk.jfrog.io/splunk/ext-releases-local</url>
		</repository>
		<repository>
			<id>spring-releases</id>
			<name>Spring Releases</name>
			<url>https://repo.spring.io/libs-release</url>
		</repository>
	</repositories>
	...
</project>

We can see that application is connecting to multiple maven repositories, such as Splunk JFrog and Spring Repository, other than the default Maven Central.

For this approach, we can create a custom settings.xml and implement a multiple mirror approach for handling to this problem. The result is looks like below xml,

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>default</id>
            <username>username</username>
            <password>password</password>
        </server>
        <server>
            <id>splunk-releases</id>
            <username>username</username>
            <password>password</password>
        </server>
		<server>
            <id>spring-releases</id>
            <username>username</username>
            <password>password</password>
        </server>
    </servers>

    <mirrors>
        <mirror>
            <id>default</id>
            <name>Default Repository</name>
            <url>https://my-artifact-repository/default/maven2/</url>
            <mirrorOf>*, !splunk-releases, !spring-releases</mirrorOf>
        </mirror>
        <mirror>
            <id>splunk-releases</id>
            <name>Splunk Local Repository</name>
            <url>https://my-artifact-repository/splunk/maven2/</url>
            <mirrorOf>splunk-releases</mirrorOf>
        </mirror>
		<mirror>
            <id>spring-releases</id>
            <name>Spring Local Repository</name>
            <url>https://my-artifact-repository/spring/maven2/</url>
            <mirrorOf>spring-releases</mirrorOf>
        </mirror>
    </mirrors>
</settings>

As we can see on above, we have multiple mirror of repositories with each pointing to different local artifact repository endpoints. We can run maven build with having this configuration as parameter.

$ mvn clean package -s settings.xml

How to Clear User Cache in Keycloak

Keycloak provides a very convenient method of reducing workload to either database or active directory, and that is by using cache mechanism. But sometimes we want to trigger clearing cache manually, for example when there is some changes into the user data which coming from external applications.

We can do that by going to Keycloak menu, click on Realm Settings, and go to Cache tabs. We can clear cache by clicking on the User Cache Clear button.

But becareful since it will clear the whole user-cache, and not a specific user only.