Kubernetes: oauth2_proxy with dynamic callback urls

We all love the simplicity of deploying applications on Kubernetes and while many tutorials out there help you get started quickly and provide a great resource for many, some of them spare important details. In this post, I try to help the community by providing a small guide on how to deploy oauth2_proxy with dynamic callback urls. But first, what is oauth2_proxy and which problem does it solve?

The README.md explains it as follows:

A reverse proxy and static file server that provides authentication using Providers (Google, GitHub, and others) to validate accounts by email, domain or group.

Okay great, so this tool comes in handy if you want to authenticate users for an application that doesn’t offer authentication by itself. Famous examples include the Kubernetes dashboard, Prometheus or Alertmanager.

There are multiple ways to solve the issue of serving apps that don’t offer authentication out-of-the-box:

  1. Don’t expose it at all and just browse it using kubectl port-forward. This way, the application is never publicly exposed on the internet.
  2. Expose it and handle authentication in a proxy sitting in front of the application using oauth2_proxy via existing providers (Microsoft, GitHub, etc.).
  3. Establish your own (federated) idendity provider to handle user authentication using i.e. dex.

For the first option everyone who needs access to these tools need cluster access, so this is not a very flexible option. The second option is definitely more interesting because we can safely expose the applications on the public internet without much effort. The third option offer the most flexiblity but is a bit of an overkill for what I’m trying to achieve. Hence, I’ll be focusing on No. 2. But we might not want to have mulitple proxies in place which handle authentication independently for the respective app but rather a single instance that can be used by all apps. Let’s go through an example:

I want to expose Alertmananger and Prometheus to the same group of people and they should be able to seemlessly switch between the applications without the need to sign-in again.

First, I’ll be using helm to install the chart for oauth2_proxy and setting some custom properties which I need for the OAuth2 provider of my choice:

helm install stable/oauth2-proxy --name login-oauth2-proxy \
--namespace xyz \
--set config.clientID="${CLIENT_ID}" \
--set config.clientSecret="${CLIENT_SECRET}" \
--set config.cookieSecret="${COOKIE_SECRET}" \
--set extraArgs.provider="azure" \
--set extraArgs.azure-tenant="${AZURE_TENANT_ID}" \
--set extraArgs.whitelist-domain=".mydomain.com" \
--set extraArgs.cookie-domain=".mydomain.com" \
--tls

clientID, clientSecret and azure-tenant can be obtained upon registering the application for Azure Active Directory integration as described here. To restrict access to only a subset of users from the Active Directory make sure to follow these instructions after. It’s important to register the url of the ingress rule that will be used for authentication (see below), in my case https://login.mydomain.com/oauth2/callback.

The cookieSecret is just a random secret that can be generated with a simple python script.

docker run -ti --rm python:3-alpine python -c 'import secrets,base64; print(base64.b64encode(base64.b64encode(secrets.token_bytes(16))));'

Worth mentioning are the whilelist-domain and cookie-domain flags which should point to the parent domain of the applications to be protected, i.e.
You want to protect prom.mydomain.com and alerts.mydomain.com then this needs to be set to .mydomain.com.

Great, now we need an ingress route that handles authentication via the proxy we just deployed. This looks as simple as this:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: login-ingress-oauth2
  namespace: xyz
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: login.mydomain.com
    http:
      paths:
      - backend:
          serviceName: login-oauth2-proxy
          servicePort: 80
        path: /oauth2
  tls:
  - hosts:
    - login.mydomain.com

Now all we have to do for the application that should be protected via our proxy is to use the auth-url and auth-signin annotations of nginx and have them reference this ingress route.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: alertmanager-ingress
  namespace: tiller
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/auth-url: "https://login.mydomain.com/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://login.mydomain.com/oauth2/start?rd=https://$host$request_uri"
spec:
  rules:
  - host: alerts.mydomain.com
    http:
      paths:
      - backend:
          serviceName: prom-prometheus-operator-alertmanager
          servicePort: 9093
        path: /
  tls:
  - hosts:
    - alerts.mydomain.com

Browsing alerts.mydomain.com will redirect to the microsoft login and after successful authentication back to the application. If you deploy multiple application using this method you won’t have to login again as the consent has been granted already and a valid cookie exists.

A few things to be mentioned:

  1. Depending on how many applications rely on the proxy, you might want to scale the oauth2_proxy deployment to ensure availability
  2. None of the explanations above indicate that you shouldn’t be taking care of proper RBAC rules in your cluster and restrict access to the applications according to the principle of least privilege.

That’s it for now, please reach out if you have further questions or remarks. Happy Sunday!

Tags: oauth2_proxy, nginx, sso, single sign-on, reverse proxy, nginx, kubernetes

Containerization of Golang applications

I’ve been a working a lot in Golang recently and even though it easily allows for single static binary compilation I find myself using Docker a lot. Why? Well, especially when it comes to container orchestration and scaling of workloads some sort of container technology is used as these build the foundation of a Pod in Kubernetes (our deployment infrastructure).

While coming up with an initial Dockerfile is easy, correctly compiling a Go application and adhere to all sorts of container best practices is still hard. Does the size of the binary matter? If so, you might want to provide some additional flags during compilation. Do you build the app outside of the container and just copy the final artifact into it or do you use multi-stage builds to have everything within an isolated environment? How do you deal with caching of layers? How do you make sure that the final container is secure and only contains whatever is needed to execute your application?

The first thing I was overwhelmed with is how much old information is still out there and that even well-known developers such as Tim Hockin (co-creator of Kubernetes) are having questions on how to actually compile a Golang application correctly. As it turns out, some flags are strictly unnecessary as of Go 1.10 but are still widely used. Ultimately, it all depends on your needs and whether you need cgo or not but even after studying a lot of blog posts I’m still not 100% sure about my approach. As it turns out, Tim created a nice skeleton project which is a good starting point in my opinion.

Furthermore, I saw a lot of different approaches in terms of runtime base image and how the build process takes place. Some are using for golang:alpine with manually installing ca-certs, tzinfo, etc. during the build stage whereas others use plain golang instead. For the final stage common choices are either scratch or alpine which still provide a larger attack surface than i.e. gcr.io/distroless/base. As with many things, there’s not a single correct approach because one might want to keep the ability to docker exec -it into a container around whereas others have better ways to debug their services.

While coming up with my current solution I had the following considerations to take into account. Local development should still be fast, the build process must be CI-friendly with clean & reproduceable builds and no additional tooling needed to secure the final image such as microscanner or clair. Hence, I created a Makefile that helps me take care of the heavy lifting and allows for fast local development where no Docker is used at all. A shortened & simplified version looks as follows:

OUT := binary-name
PKG := github.com/package
VERSION := $(shell git describe --always --dirty)
PKG_LIST := $(shell go list ${PKG}/...)
GO_FILES := $(shell find . -name '*.go')

build:
	go build -i -v -o ${OUT} -ldflags="-X main.version=${VERSION}" ${PKG}

test:
	@go test -short ${PKG_LIST}

vet:
	@go vet ${PKG_LIST}

errorcheck:
	@errcheck ${PKG_LIST}

lint:
	@for file in ${GO_FILES} ;  do \
		golint $$file ; \
	done

container:
	@docker build --build-arg VERSION=${VERSION} -t registry/image:${VERSION} .

container-push:
	@docker push registry/image:${VERSION}

run: build
	./${OUT}

clean:
	-@rm ${OUT} ${OUT}-*

.PHONY: run build vet lint errorcheck

I’ll talk about -ldflags in a bit, so don’t worry about it for now. Since the regular go build command doesn’t do static analysis on the project files, I created steps like vet (checks for correctness/suspicious constructs), lint (style mistakes) and errorcheck (missing error handling) I can run whenever I feel like it. This is not done implicitly through another step such as build because my CI system takes care of these things too. The rest of the file should be self-explanatory if you’re familiar with make.
Now, the following Dockerfile is only used in my CI system for which I don’t mind it to fetch the dependencies during each build.

# Build stage
FROM golang:1.11.4 AS build-env

LABEL maintainer="Jonas-Taha El Sesiy <[email protected]>"

WORKDIR /project
ARG VERSION
COPY main.go go.mod go.sum ./
RUN bash -c "go get -d &> /dev/null" && \
    CGO_ENABLED=0 GOOS=linux go build -ldflags "-X main.version=${VERSION} -s -w" -a -o app .

# Final stage
FROM gcr.io/distroless/base
COPY --from=build-env /project/app .
CMD ["./app"]

I’m using multi-stage builds with the latest Golang version as the base image. For the final stage, I opted for distroless even though the final image is bigger than the other choices. Note that I’m using go modules for dependency management introduced in Go 1.11 for which I copy the go.mod and go.sum files into the container.
As mentioned before, there are a couple of flags passed onto the go compiler via -ldflags. -X main.version=abc allows me to pass on the version information to the binary which is then used within the app in some fashion. -s -w disables the symbol table and the generation of debug data in form of DWARF in order to reduce the size of the binary which is useful for my production image.

This is just my take on this. If you have suggestions for improvements or any other remarks, please reach out. Thanks! :wave:

Tags: docker, container, golang, go

DV lottery - What is that?, Part 3

Alright, this is the last part of the series on the ins and outs of the DV lottery. If you haven’t read the previous articles already, make sure to find out everything about the interview process in the first part and the some of the initial actions to take arriving in the country if you’re among the lucky ones in the second part.
In this part, I’ll be talking about getting a driver’s license, job search, and international travel as a resident (how to keep your status as a resident).

Driver’s license

As a newcomer to a foreign country you’re required to operate a vehicle at some point in time. If I think about my time as a tourist in the US it was easy as many states allow driving with a foreign driver’s license up to three months. Well, if you’re on an immigrant visa it’s different. In California where I live, the law says you’re only allowed to use a foreign license for 10 days if there’s an immigration intent. In crowded places like the San Fransisco Bay Area it’s almost impossible to get an appointment that fast.
If you’re hoping for a clear guidance on what to do in this case - I don’t have it.

Some people keep driving with their foreign license, some people use any of the available car sharing services to get around. The good thing is though, that once you passed the knowledge test you’re allowed to drive if someone at the age of 25 who owns a valid driver’s license accompanies you. This should help you to familarize yourself with your new environment and lets you practice for your driving test. For me the whole process took about 3 month and cost 35$.

Note: The US driver’s license is much more than just a license. It’s commonly used for age checks and serves as a valid travel document for domestic flights. Starting October 1st, 2020, boarding domestic flights requires the ownership of a REAL ID driver’s license or ID card. More info on this can be found here.

Finding a job

Even though becoming a US resident doesn’t mean you have to work for a US company or work at all but I assume that most of us need to make a living somehow so getting a job was one of my major concerns. Unfortunately, there’s no general rule of thumb I can provide you with because finding a job is strongly dependent on the industry you are operating in. For me applying through i.e. glassdoor wasn’t successful at all but instead going to Meetups and meeting people in person worked pretty well. I read that only a fraction of available jobs is being posted online and networking is so much more important than I was used to it from Europe. In general, I’d suggest at least 3 months in which one can settle and interview with a lot of companies to find a good job.

Travel

The article is getting quite long already but this is an important part, so bear with me. A big topic is travelling internationally as a resident as you’re supposed to be in the US. Nonetheless, having vacation and staying away for a couple of weeks is usually not an issue. If you can provide documentation that you’re actually living in the US and justify your trip, there’s nothing to worry about even with frequent travels. But if you plan on staying away longer than one year then you must apply for a reentry permit as your permanent resident card becomes technically invalid after this period.

A topic I haven’t covered here is the process of naturalization which means becoming a citizen. As I have yet to explore this myself, I can only point you to the official website.

This was the last part on the topic for now, please reach out if you have any questions or remarks!

Tags: diversity visa, green card, lottery, USA

DV lottery - What is that?, Part 2

As promised back in August, I’m finally continuing my post about the DV lottery. In this part I’m going to explain how I finally got the physical green card (compared to the temporary stamp in my passport) and what else I’ve been doing the whole time. Make sure to check out the first part if you haven’t read it yet.

After successfully going through the application process for the green card at the US embassy in Frankfurt, Germany I received my passport (with a temporary visa) and an envelope with my immigration documents. This envelope is sealed and under no circumstance are you allowed to open it or remove anything attached to it. The temporary visa has a shortened validity depending on the date of the medical examination plus 6 months. The soon-to-be resident must immigrate to the US prior to the expiration of this visa or the medical exam has to be repeated and a new visa needs to be issued. So here’s what you need to know about the pitfalls of using this visa until you receive the final document.

Immigration and Green card

The first thing to do is of course flying out to your prospective home country and handing over the sealed envelope at any port of entry. The officer will open the envelope to make sure the documents are complete and put the info into the system. He’ll then ask you about your home address because that’s the corresponding address for the United States Citizenship and Immigration Services (USCIS) to send your green card to once you paid the issuing fee of 165$. Furthermore, he’ll welcome you to the USA :+1:. What next? Well technically nothing needs to be done at this point in time except for wait for your social security card (which should arrive within 30 days) and the green card (arrival supposedly within 120 days) in your mailbox.

In my case this totally didn’t work at all so I needed to reach out to the Social Security Administration (SSA) and manually apply for the card. Also I started to getting appointment notices for the so-called biometrics appointment at the USCIS field office located next to my home address. These notices usually don’t apply for diversity visa recipients as they have their biometrics taken already at the embassys. Even after attending one of the appointments and having my biometrics taken again, I continued receiving these notices which proved my suspicion that something is wrong. I called the USCIS multiple times and was finally able to talk to an immigration officer who didn’t know what was going on with the notices and also not why there’s such a long delay in processing my case (120 days were long overdue at this point).
There was one last hope: The CIS ombudsman. The office of the ombudsman can be consulted for cases which are long overdue or in order to file complaints, etc. Two days after filing my case with them there was an update on my case (the green card has been mailed) and I closed my case with them immediately again which must be a coincidence, but usually this office is a good point of contact.
Just to let you know: Once the physical green card has been sent out, the temporary visa in your passport becomes invalid. I learned it the hard way through second screening in Austin, TX but that’s a different story…

SIM Card

As a German I was shocked about the prices for cellular service of any kind in the US. You can easily pay up to 70$ for unlimited data, text and voice here which is almost double the price of what I’ve been paying back in Germany but anyway… There are four major networks that operate in the US: AT&T, T-Mobile, Verizon and Sprint. I’m not going into detail on this any further except for this tiny remark: There’s a difference between GSM and CDMA, so make sure your phone is compatible ;)

Personally, I decided to go with what is called a Mobile Virtual Network Operator (MVNO). They share the frequencies of major networks (sometimes even all of them at once, i.e. Google Fi) and usually offer better deals compared to walking into the name brand stores. My MVNO is called Mint and operates on the T-Mobile network. At times, there might be reduced speed if the network is busy since direct T-Mobile customers are preferred over MVNOs but I haven’t experienced it yet and I think it’s fair with regard to the cost benefit. A downside of MVNOs is that they usually have very few or no stores at all, so you need to order it online which can be a little inconvenient especially if you need a phone right from the beginning (i.e. to Uber home from the airport). Be sure to check the coverage maps of the network operator, no matter if MVNO or direct brand as there might be huge differences depending on your area.

Bank Account

One of the first things you probably want to do is opening up a bank account. I’ve been a huge fan of online banks and looked into Simple only to find out that they’re exclusively serving US citizens. So I did some research for comparable offers and finally found Capital One to be a good alternative. They offer a great ATM network, no fees and everything is easily managed through their website or app. There are multiple types of bank accounts one can open but since I’m not here to provide financial advice by any means let’s stick with a traditional Saving’s acccount. Opening up the account is straight-forward online or through one of their very few branches across the country. All you need is an address for shipment of your card, a phone number in your name and your social security number.

If you apply for a credit card right away, you probably will be denied or get a very low limit on it. To build up credit, it’s best to start out with a Secured Credit Card. There’s another possibility if you happen have a credit card from an international operating institution such as American Express already in your home country. They offer to transfer your history with them and issue a new card for the US with comparable conditions as in your home country which simplifies things a lot.

Note: If you try opening up the account right after your arrival, there’s probably no credit history on you in any of the systems they check against. This means they won’t be able to verify that you are an acutal person and this is why you need to have a phone number in your name. I believe the idea is that i.e. if you went to an AT&T store to get a SIM card, they have already seen you in person.

Credit history

You’re new to the country and nobody knows about your spending habits and whether you are a reliable customer or not. Expect huge down payments and/or insane interest rates as companies try to mitigate the risk of you not paying your bills. A common approach to build up your credit without wasting huge amounts of money on interest payments is to buy everything with a credit card and pay it off in full every month prior to doing bigger investments such as getting a car or buying a house (if you can wait that long). Also make sure to put your name on the utility bills of the place where you are staying if possible which also increases your credit.

That’s it for now. I’ll continue in the next part on how to find a job, travel as a resident and much more, stay tuned!

Tags: diversity visa, green card, lottery, USA