Using Dex for authentication
Dex is an identity service that uses OpenID Connect to drive authentication for other apps.
Dex acts as a portal to other identity providers through “connectors.” This lets Dex defer authentication to LDAP servers, SAML providers, or established identity providers like GitHub, Google, and Active Directory. Clients write their authentication logic once to talk to Dex, then Dex handles the protocols for a given backend.
This section shows you how to set up GitHub authentication using Service Mesh Manager. To set up other authentication backends such as Active Directory or LDAP, see the DEX Connectors documentation.
Enable GitHub authentication
As GitHub is an OAuth 2 provider, Service Mesh Manager requires a bridge between OAuth 2 (or any other authentication backend) and OIDC.
Prerequisites
Before starting to set up GitHub authentication to Service Mesh Manager, make sure that you have already:
- Exposed the Service Mesh Manager dashboard to a public, ssl-protected URL.
- Installed external-dns on the cluster for registering public DNS records.
- Registered an
OAuth 2 App
in your GitHub account via this URL: https://github.com/settings/applications/new - Installed a recent version of
helm
on your computer.
You need the following information to follow this guide:
GITHUB_CLIENT_ID
: The Client ID from the GitHub OAuth 2 registration.GITHUB_CLIENT_SECRET
: The Client Secret from the GitHub OAuth 2 registration.GITHUB_ORG_NAME
: The name of the GitHub organization to authenticate against. If you want to support multiple organizations, consult the Dex manual.GITHUB_ADMIN_TEAM_NAME
: The name of the GitHub team that contains the users who receive administrative privileges.DEX_EXTERNAL_URL
: The URL where Dex will be exposed. This must be separate from the dashboard URL.SMM_DASHBOARD_URL
: The URL where the Service Mesh Manager dashboard is exposed.OIDC_CLIENT_SECRET
: The secret to be used between Dex and the Service Mesh Manager authentication backend (can be any random string).
To follow the examples, export these values as environment variables from your terminal, as these will be needed in multiple steps:
export GITHUB_CLIENT_ID=<***>
export GITHUB_CLIENT_SECRET=<***>
export GITHUB_ORG_NAME=my-github-org
export GITHUB_ADMIN_TEAM_NAME=admin
export DEX_EXTERNAL_URL=dex.example.org
export SMM_DASHBOARD_URL=smm.example.org
export OIDC_CLIENT_SECRET=$(openssl rand -base64 32) # or any random string
Create namespace for Dex
Dex will be installed into its own namespace for isolation. Create the namespace for it:
kubectl create ns dex
Dex will be exposed externally using Istio, so enable Istio sidecar injection on the namespace:
kubectl label ns dex istio.io/rev=cp-v115x.istio-system
Create MeshGateway for Dex
GitHub needs to access Dex to invoke the OAuth 2 callback, so that Dex can understand what was the result of the authentication on the GitHub side.
Create an externally available MeshGateway:
cat > dex-meshgateway.yaml <<EOF
apiVersion: servicemesh.cisco.com/v1alpha1
kind: IstioMeshGateway
metadata:
labels:
app.kubernetes.io/instance: dex
app.kubernetes.io/name: dex-ingress
name: dex-ingress
namespace: dex
spec:
istioControlPlane:
name: cp-v115x
namespace: istio-system
deployment:
metadata:
labels:
app.kubernetes.io/instance: dex
app.kubernetes.io/name: dex-ingress
gateway-name: dex-ingress
gateway-type: ingress
replicas:
max: 1
min: 1
count: 1
service:
metadata:
annotations:
external-dns.alpha.kubernetes.io/hostname: ${DEX_EXTERNAL_URL}.
ports:
- name: http2
port: 80
protocol: TCP
targetPort: 8080
- name: https
port: 443
protocol: TCP
targetPort: 8443
type: LoadBalancer
type: ingress
---
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
labels:
app.kubernetes.io/instance: dex
app.kubernetes.io/name: dex-ingress
name: dex-ingress
namespace: dex
spec:
selector:
app.kubernetes.io/instance: dex
app.kubernetes.io/name: dex-ingress
servers:
- hosts:
- '*'
port:
name: http
number: 80
protocol: HTTP
- hosts:
- '*'
port:
name: https
number: 443
protocol: HTTPS
tls:
credentialName: dex-ingress-tls
mode: SIMPLE
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
labels:
app.kubernetes.io/instance: dex
app.kubernetes.io/name: dex-ingress
name: dex-ingress
namespace: dex
spec:
gateways:
- dex-ingress
hosts:
- '*'
http:
- match:
- uri:
prefix: /
route:
- destination:
host: dex
port:
number: 80
EOF
kubectl apply -f dex-meshgateway.yaml
Get certificates for Dex
The secret referenced in the MeshGateway resource is not yet available. To secure the communication between the end-user’s browser and your Dex installation, enable the Let’s Encrypt support for gateways in Service Mesh Manager:
cat > certs.yaml <<EOF
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: dex-issuer
namespace: dex
spec:
acme:
email: noreply@cisco.com
preferredChain: ""
privateKeySecretRef:
name: smm-letsencrypt-issuer
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- http01:
ingress:
class: nginx
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dex-tls
namespace: dex
annotations:
acme.smm.cisco.com/gateway-selector: |
{
"app.kubernetes.io/instance": "dex",
"app.kubernetes.io/name": "dex-ingress"
}
spec:
dnsNames:
- ${DEX_EXTERNAL_URL}
duration: 2160h0m0s
issuerRef:
group: cert-manager.io
kind: Issuer
name: dex-issuer
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
renewBefore: 360h0m0s
secretName: dex-ingress-tls
usages:
- server auth
- client auth
EOF
kubectl apply -f certs.yaml
After executing the previous commands, check that the Certificate has been successfully issued by running the kubectl get certificate
command. The output should be similar to:
NAME READY SECRET AGE
dex-tls True dex-ingress-tls 24h
If the READY column shows True, then the Certificate has been issued. If not, refer to the Cert Manager documentation for troubleshooting the issue.
Provision Dex
Now you can install Dex onto the namespace using helm
. First create a file called dex-values.yaml
for the Dex installation:
cat > dex-values.yaml <<EOF
---
config:
issuer: https://${DEX_EXTERNAL_URL}
storage:
type: kubernetes
config:
inCluster: true
connectors:
- type: github
id: github
name: GitHub
config:
clientID: $GITHUB_CLIENT_ID
clientSecret: "$GITHUB_CLIENT_SECRET"
redirectURI: https://${DEX_EXTERNAL_URL}/callback
orgs:
- name: $GITHUB_ORG_NAME
loadAllGroups: true
oauth2:
skipApprovalScreen: true
staticClients:
- id: smm-app
redirectURIs:
- "https://${SMM_DASHBOARD_URL}/auth/callback"
name: 'Cisco Service Mesh Manager'
secret: ${OIDC_CLIENT_SECRET}
service:
enabled: true
ports:
http:
port: 80
https:
port: 443
EOF
Run the following commands to install Dex using these values:
helm repo add dex https://charts.dexidp.io
helm install -n dex dex -f dex-values.yaml dex/dex
Verify that Dex has started successfully by running the kubectl get pods -n dex
command. The output should be similar to:
NAME READY STATUS RESTARTS AGE
dex-6d879bb86d-pxtvm 2/2 Running 1 20m
dex-ingress-6885b4f747-c5l96 1/1 Running 0 24m
Configure SMM to use OIDC provider
Enable Dex as an OIDC provider to Service Mesh Manager by patching the ControlPlane resource:
cat > smm-oidc-enable.yaml <<EOF
spec:
smm:
auth:
oidc:
enabled: true
client:
id: smm-app
issuerURL: https://${DEX_EXTERNAL_URL}
secret: ${OIDC_CLIENT_SECRET}
groups:
claim: groups
prefix: 'oidc:'
username:
claim: email
prefix: 'oidc:'
EOF
kubectl patch --type=merge --patch "$(cat smm-oidc-enable.yaml )" controlplane smm
- If you are using Service Mesh Manager in Operator Mode, then the Istio deployment is updated automatically.
- If you are using the imperative mode, run the
smm operator reconcile
command to apply the changes.
Create user mapping
After logging in, the users will be mapped to have the:
- Username of
oidc:<email-of-the-github-user>
, and the - groups of
oidc:$$GITHUB_ORG_NAME:<team-name>
for each of the GitHub Teams the user is a member of.
By default, these users and groups cannot modify the resources in the target cluster, so you need to create the ClusterRoleBinding right for these Groups or Users. For example, to grant administrative access to the users in the $GITHUB_ADMIN_TEAM_NAME
GitHub Team, run the following command:
cat > allow-admin-access.yaml <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: oidc-admin-access
subjects:
- kind: Group
name: 'oidc:$GITHUB_ORG_NAME:$GITHUB_ADMIN_TEAM_NAME'
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f allow-admin-access.yaml
The groups a given user belongs to is shown in the right hand menu on the user interface:
In this example, the username is oidc:test@example.org
and the user belongs to only one group, called oidc:example-org:test
.
Verify login
To test that the login works, navigate to the URL where the Service Mesh Manager dashboard is exposed ($SMM_DASHBOARD_URL
), and select Sign in with OIDC.