Secure Serverless with OpenFaaS
mikeyGlitz
Posted on May 12, 2021
During my career as a professional in the Software Industry, I've witnessed the rise of DevOps. DevOps is the practice of merging your development team (programmers) with your operations team (think the server admins and net-ops guys).
While learning about servers has its ups and downs. You get to celebrate the triumphs of finally getting your hosting platform up and running while dealing with the frustration that is the nuance of configuration files. It's probably safe to say that when you're in college or boot-camp learning to become a developer, your ideal day-in-the-life is not building up your development platform and spending days delving through configuration files and ACL permissions while hoping your service comes up in the end.
Enter Serverless
Serverless is a buzz word these days that often gets misunderstood. Does serverless mean that there are no servers? Quite the contrary. There are servers in a serverless platform. The main difference is that there isn't a server that you have to actively manage. Any services deployed on a serverless platform are scaled up and executed when they're requested and scaled down once the execution is completed and the service is no longer needed.
The biggest payoff with this architecture from a development standpoint is that you no longer need to be concerned about provisioning infrastructure. Instead, you specify an event type (i.e. HTTP request, Message Bus, CRON trigger), and a handler function (your code) and the platform builds out the application in a container and handles the execution for you.
Where Does OpenFaaS fit into this?
OpenFaas is a service which allows you to deploy serverless functions on a self-hosted cloud environment (i.e. Kubernetes). This tutorial will cover how to deploy OpenFaaS to Kubernetes and configure the portal with authentication.
⚠ The authentication method utilized in this tutorial is not officially supported by OpenFaas. I'm using the Open Source community edition. In order to support OIDC or OAUTH, you need an enterprise license.
Setting up OpenFaaS
OpenFaaS provides a helm chart which can be used for setting up an OpenFaaS Kubernetes deployment quickly. This tutorial will utilize a combination of the OpenFaaS helm chart and the OAUTH2 Proxy chart to set up authentication with Keycloak
OAuth2 Proxy Set-Up
Assuming you have a Keycloak server set up and registered a new client to your Keycloak realm, you will need the client-id and the client-secret in order to set up the OAuth proxy.
The following Ansible task can aid in setting up a Keycloak client.
- name: Create Keycloak client
community.general.keycloak_client:
state: present
auth_client_id: admin-cli
auth_keycloak_url: "{{ keycloak_server }}/auth"
auth_username: "{{ keycloak_user }}"
auth_password: "{{ keycloak_password }}"
auth_realm: master
name: Openfaas Portal
client_id: openfaas
client_authenticator_type: client-secret
secret: "{{ client_secret }}"
realm: hausnet
protocol_mappers:
- config:
included.client.audience: "openfaas-portal"
id.token.claim: "false"
access.token.claim: "true"
name: openfaas-portal-mapper
protocol: openid-connect
protocolMapper: oidc-audience-mapper
- name: "openfaas-group-mapper"
protocol: "openid-connect"
protocolMapper: "oidc-group-membership-mapper"
config:
id.token.claim: "true"
access.token.claim: "true"
claim.name: "groups"
userinfo.token.claim: "true"
redirect_uris:
- "{{ openfaas_endpoint }}/*"
web_origins:
- "*"
validate_certs: no
ℹ The variables in use by the ansible role
openfaas_endpoint
the URL which OpenFaaS will be listeningkeycloak_server
the URL where Keycloak will be listeningkeycloak_user
the username used to authenticate with Keycloak in order to create the keycloak clientkeycloak_password
the password of the user used to authenticate with Keycloak in order to create the Keycloak clientclient_secret
the secret used for authentication. This value will be set when the client is created in Keycloak
The following chart demonstrates how to set up the OAuth proxy using Terraform.
resource "helm_release" "rel_oauth2_proxy" {
repository = "https://k8s-at-home.com/charts/"
chart = "oauth2-proxy"
name = "auth"
namespace = "openfaas"
values = [
<<YAML
extraArgs:
provider: keycloak
email-domain: "*"
scope: "openid profile email"
login-url: https://${vars.keycloak}/auth/realms/${vars.realm}/protocol/openid-connect/auth
redeem-url: https://${vars.keycloak}/auth/realms/${vars.realm}/protocol/openid-connect/token
validate-url: https://${vars.keycloak}/auth/realms/${vars.realm}/protocol/openid-connect/userinfo
keycloak-group: /admin
ssl-insecure-skip-verify: true
ingress:
enabled: true
hosts:
- ${vars.openfaas_domain}
path: /oauth2
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: cluster-issuer
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
tls:
- secretName: oauth-proxy-tls
hosts:
- ${vars.openfaas_domain}
extraEnv:
- name: OAUTH2_PROXY_CLIENT_ID
value: ${vars.client_id}
- name: OAUTH2_PROXY_CLIENT_SECRET
value: ${vars.client_secret}
- name: OAUTH2_PROXY_COOKIE_SECRET
value: ${vars.encryption_key}
YAML
]
set {
name = "proxyVarsAsSecrets"
value = "false"
}
}
ℹ
client_id
,client_secret
,keycloak
, andrealm
are variables which are provided using Terraform variables
Deploying OpenFaaS
With the OAuth2 Proxy deployed, it's now time to deploy OpenFaas
resource "helm_release" "rel_openfaas" {
repository = "https://openfaas.github.io/faas-netes/"
name = "openfaas"
chart="openfaas"
namespace = "openfaas"
set {
name = "functionNamespace"
value = "openfaas-fn"
}
set {
name = "generateBasicAuth"
value = "false"
}
set {
name = "basic_auth"
value = "false"
}
set {
name = "serviceType"
value = "ClusterIP"
}
}
⚠ OpenFaaS has an official method of handling OIDC/OAuth authentication; however, that's behind a pay-wall. Here we're turning off authentication since it's being outsourced to our OAuth2 proxy created in the previous step.
We set up the Kubernetes Ingress to expose access to OpenFaas through our OAuth2 proxy. Below is an example on how to set up the ingress using Kubernetes manifests:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: openfaas-gateway
namespace: openfaas
annotations:
kubernetes.io/ingress-class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
cert-manager.io/cluster-issuer: cluster-issuer
nginx.ingress.kubernetes.io/upstream-vhost: $service_name.$namespace.svc.cluster.local:8080
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Origin "";
proxy_hide_header l5d-remote-ip;
proxy_hide_header l5d-server-id;
spec:
rules:
- host: "functions.haus.net"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gateway
port:
number: 8080
tls:
- hosts:
- "functions.haus.net"
secretName: openfaas-tls-cert
Once the deployment completes, OpenFaaS should be available from the ingress endpoint. In this example, I set the endpoint to https://functions.haus.net
.
Posted on May 12, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
August 12, 2024