Istio and proxy-protocol

When you search for solutions on the internet it is sometimes very difficult to know if what is proposed is going to work in your environment. The challenge comes from the fact that not everyone identifies the version they were working with at the time they applied this solution.

I find this snippet of YAML to be applied to my istio deployment to allow some headers to be properly passed on with the requests to the destination service.

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: proxy-protocol
  namespace: istio-system
spec:
  configPatches:
    - applyTo: LISTENER
      patch:
        operation: MERGE
        value:
          listener_filters:
            - name: envoy.listener.proxy_protocol
            - name: envoy.listener.tls_inspector
  workloadSelector:
    labels:
      istio: ingressgateway

Once applied, I tested but nothing changed and I still get the errors:

ERR_TOO_MANY_REDIRECTS

I then decide to see if restarting the istio ingress pod would fix things.

Well…

The pod is not coming back so I pull the logs and rapidly reads to identify what is causing this issue. I finally spot a few lines:

2022-07-12T20:39:29.975846Z	error	envoy misc	Using deprecated extension name 'envoy.listener.proxy_protocol' for 'envoy.filters.listener.proxy_protocol'. This name will be removed from Envoy soon. Please see https://www.envoyproxy.io/docs/envoy/latest/version_history/version_history for details. If continued use of this filter name is absolutely necessary, see https://www.envoyproxy.io/docs/envoy/latest/configuration/operations/runtime#using-runtime-overrides-for-deprecated-features for how to apply a temporary and highly discouraged override.
2022-07-12T20:39:30.421115Z	error	envoy misc	Using deprecated extension name 'envoy.listener.proxy_protocol' for 'envoy.filters.listener.proxy_protocol'. This name will be removed from Envoy soon. Please see https://www.envoyproxy.io/docs/envoy/latest/version_history/version_history for details. If continued use of this filter name is absolutely necessary, see https://www.envoyproxy.io/docs/envoy/latest/configuration/operations/runtime#using-runtime-overrides-for-deprecated-features for how to apply a temporary and highly discouraged override.
2022-07-12T20:39:30.429091Z	warning	envoy config	gRPC config for type.googleapis.com/envoy.config.listener.v3.Listener rejected: Error adding/updating listener(s) 0.0.0.0_8443: Didn't find a registered implementation for name: 'envoy.listener.proxy_protocol'
0.0.0.0_8080: Didn't find a registered implementation for name: 'envoy.listener.proxy_protocol'

So I delete the EnvoyFilter and everything comes back.

So envoy.listener.proxy_protocol does not work with istio 1.13.x? I will have to read more to figure that part out.

Spring Beans not Instantiating

I had not seen this error before:

No qualifying bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' available

It took a little bit of research to find that if you do not have your application.yaml with the Spring Security section for this bean, it will not be able to instatiate one and you get the error.

To make it more difficult, I was specifying this module in gradle and I was expecting things to work. Asuming…

Once I added:

spring:
  security:
    oauth2:
      client:
        registration:
          nameItSomething:
            authorization-grant-type: client_credentials
            client-id: clientNameYouHave
            client-secret: DontShareYourSecretOnTheInternet
        provider:
          nameItSomething:
            token-uri: https://oidcServer/protocol/openid-connect/token

That ClientRegistrationRepository bean started to have a life.

Next bean… Same… I need to add a section for the caching in my application.yaml.

Dear Checkstyle

I am not a big fan of forced styles and all these errors that comes with it.

I know, I know… If you are on a team of more people, you don’t have much of a choice otherwise you end up with style chaos and naming convention that are closer to a standup comedian number than logic.

I am just not a big fan…

We have a style for the member name in our classes that only allows for letters and number but I did a class to match the json returned from Azure OIDC so it is all lowercase name with underscore. Checkstyle would not let this through so I learned quickly how to turn that off for my class

This is the module in Checkstyle:

<module name="SuppressionCommentFilter">
    <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
    <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
    <property name="checkFormat" value="$1"/>
</module>

All you have to do is a comment:

// CHECKSTYLE.OFF: MemberName

and after my class definition I can simply turn it back on:

// CHECKSTYLE.ON: MemberName

Then I could discuss with a team mate and disagree about having an annotation (@jsonproperty(“name_with_underscore”)) for each member name to respect the checkstyle and work with the json. What is the simplest will always win in my mind and not following made up rules for the sake of the rule.

Automating Keycloak with Java

We needed to automate some tasks in our Keycloak so that some elements were created as events were happening.

I find that the Java library for Keycloak is not always intuitive. It does not help that my searches for the documentation or examples returned all sorts of contradicting results.

In this case adding an Identity Provider seems to have many ways to be done but only 1 worked for me.

What works:

destinationRealmResource.identityProviders().create(identityProviderRepresentation);

Alternative code I had seen that I could not get to work for me:

destinationRealmResource.toRepresentation().addIdentityProvider(identityProviderRepresentation);
var clientRes = client.updateRealm(destinationRealmResource.toRepresentation());

And this did not work for me:

destinationRealmResource.toRepresentation().setIdentityProviders(List.of(identityProviderRepresentation));
var clientRes = client.updateRealm(destinationRealmResource.toRepresentation());

This was done with Keycloak 15.

In my troubleshooting I also noticed that having some invalid strings in your representation configuration can cause the creation to fail. I am not a fan of the Map<String, String> for the configuration because that leaves room for a lot of mistakes.

Breaking istio in microk8s

I was running microk8s version 1.20 on my laptop and decided to upgrade it to 1.22 since it is the newest stable version.

That was easy:

sudo snap refresh microk8s --channel=1.22/stable

After the upgrade I noticed that many applications in the istio-system were not working. I taught that deleting the pod would recreate it and fix the issue but they kept failing.

When I try to remove istio I get an error:

sudo microk8s.disable istio
Disabling Istio
Error: unknown flag: --purge

And I am stuck in this state.

I have not found any solution to this yet.

MS Team for Linux

Where is the configuration for my credentials?

That is how I started my day because I wanted to use my Ubuntu laptop today. I started team and it was clearly trying to login to my previous employers account. Infinite loop that probably guarantees my ip to be flagged.

After a few DuckDuckGo searches I could not find anything other than the trivial guides to install the snap on Ubuntu.

I tried looking at the file system and I was not able to figure out where the credentials are configured.

So… I cleared all the caches to start fresh and it worked well enough to get me going.

cd
cd snap/teams-for-linux
rm -Rf 172
rm -Rf 182
rm -Rf current

The 172 and 182 where the running directories in my case but I assume that you might have different numbered directories based on your running environment/version.

After starting Team, it has recreated the 182 directory and current symlink.

Dependency Hell

It is not a secret even if we try to hide from it.

The dependencies in writing any application today is a nightmare and a lot of work to maintain straight.

Google has a tool to look at some open-source project and as much as it is not the first of such tool, I like the graph mode available.

https://deps.dev

I was trying to find something interesting to look at but most java projects I looked at had simple graphs. I found this one that makes the tool visual shine a bit:

https://deps.dev/maven/com.android.tools.build%3Agradle/2.3.0/dependencies/graph

Interesting tool.

Keycloak Identity Provider ID

That took a couple of hours to figure out so let’s share some notes.

I have code that creates the required Keycloak Realms and configures a few items in each of them.

One of those configuration is to create the Identity Provider so that we can link users to another realm. Internal SSO if you will.

I tested this with Keycloak 11.0.3.

I did not understand that the Identity Provider ID needed to be one of the specific values since it is only a string that you pass to it. Sometimes I wish they could use an enum to help users make sense of it quickly.

After getting errors that it was a required fields and trying a few values that did not make sense to Keycloak.

10:39:07.587 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "{"errorMessage":"Invalid identity provider id [password]"}"

10:41:50.814 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "{"errorMessage":"Invalid identity provider id [EmailAuthProviderID]"}"

I tried keycloak-oidc and it worked. So the value needs to be one of these:

  • saml
  • oidc
  • keycloak-oidc

You could also use one of the social identity provider.

I also understood to take the config from the endpoint:

http://192.168.1.50:8080/auth/realms/Customer/.well-known/openid-configuration

Sample code:

IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation();
identityProviderRepresentation.setDisplayName(IDP);
identityProviderRepresentation.setProviderId("keycloak-oidc");
identityProviderRepresentation.setAlias(IDP);
Map<String, String> config = new HashMap<>();
config.put("issuer", "http://192.168.1.50:8080/auth/realms/Customer");
config.put("authorization_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/auth");
config.put("token_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/token");
config.put("introspection_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/token/introspect");
config.put("userinfo_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/userinfo");
config.put("end_session_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/logout");
config.put("jwks_uri", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/certs");
config.put("check_session_iframe", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/login-status-iframe.html");
config.put("grant_types_supported", "[\"authorization_code\",\"implicit\",\"refresh_token\",\"password\",\"client_credentials\"]");
config.put("response_types_supported", "[\"code\",\"none\",\"id_token\",\"token\",\"id_token token\",\"code id_token\",\"code token\",\"code id_token token\"]");
config.put("subject_types_supported", "[\"public\",\"pairwise\"]");
config.put("id_token_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\"]");
config.put("id_token_encryption_alg_values_supported", "[\"RSA-OAEP\",\"RSA1_5\"]");
config.put("id_token_encryption_enc_values_supported", "[\"A256GCM\",\"A192GCM\",\"A128GCM\",\"A128CBC-HS256\",\"A192CBC-HS384\",\"A256CBC-HS512\"]");
config.put("userinfo_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\",\"none\"]");
config.put("request_object_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\",\"none\"]");
config.put("response_modes_supported", "[\"query\",\"fragment\",\"form_post\"]");
config.put("registration_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/clients-registrations/openid-connect");
config.put("token_endpoint_auth_methods_supported", "[\"private_key_jwt\",\"client_secret_basic\",\"client_secret_post\",\"tls_client_auth\",\"client_secret_jwt\"]");
config.put("token_endpoint_auth_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\"]");
config.put("claims_supported", "[\"aud\",\"sub\",\"iss\",\"auth_time\",\"name\",\"given_name\",\"family_name\",\"preferred_username\",\"email\",\"acr\"]");
config.put("claim_types_supported", "[\"normal\"]");
config.put("claims_parameter_supported", "false");
config.put("scopes_supported", "[\"openid\",\"offline_access\", \"profile\",\"email\",\"address\",\"phone\",\"roles\",\"web-origins\",\"microprofile-jwt\"]");
config.put("request_parameter_supported", "true");
config.put("request_uri_parameter_supported", "true");
config.put("code_challenge_methods_supported", "[\"plain\",\"S256\"]");
config.put("tls_client_certificate_bound_access_tokens", "true");
identityProviderRepresentation.setConfig(config);

Finally, I have creation of the Identity Provider in my realm and I can link users to it.

No JDK 16 for Gradle 6

That was an annoying configuration where my project was using JDK 11 but I did not see that my Gradle settings were using JDK 16 and that kept giving me the error:

Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:

After I removed JDK 16 from my project, it pointed me to the fact that Gradle had no JDK configured. Hint.

Now that everything is using JDK 11, life is beautiful again in my IDE.

Development Software Management

I have used a simple tool for many years to manage the development software I need on my Linux workstation:

The installation is very simple has highlighted on their home page:

curl -s "https://get.sdkman.io" | bash

A bit scary to be running a script that you download straight into a shell but you can do as you see fit to examine the script first if you prefer.

I use it to install Java, Gradle, Kotlin, Spark, VisualVM and it allows you to try a few other framework. You can even decided which Java vendor you want to use.

A big advantage is that it installs all these software in your home directory and it does not affect the system. You can also quickly switch from a version to another and that has proven very useful more than once.