Authentication Providers with AD
Prerequisites
- Microsoft AD (with LDAP protocol)
- Users and Groups
- Assigned Roles
OpenShift RBAC with AD
Configuring External Authentication Providers
OpenShift supports a number of different authentication providers, and you can find the complete list in the understanding identity provider configuration. One of the most commonly used authentication providers is LDAP, whether provided by Microsoft Active Directory or by other sources.
OpenShift can perform user authentication against an LDAP server, and can also configure group membership and certain RBAC attributes based on LDAP group membership.
Background: LDAP Structure
In this environment we are providing LDAP with the following user groups:
ocp-user
: Users with OpenShift access- Any users who should be able to log-in to OpenShift must be members of this group
- All of the below mentioned users are in this group
ocp-normal-dev
: Normal OpenShift users- Regular users of OpenShift without special permissions
- Contains:
normaluser1
,teamuser1
,teamuser2
ocp-fancy-dev
: Fancy OpenShift users- Users of OpenShift that are granted some special privileges
- Contains:
fancyuser1
,fancyuser2
ocp-teamed-app
: Teamed app users- A group of users that will have access to the same OpenShift Project
- Contains:
teamuser1
,teamuser2
Examine the OAuth configuration
Since this is a pure, vanilla OpenShift 4 installation, it has the default OAuth resource. You can examine that OAuth configuration with the following:
oc get oauth cluster -o yaml
You will see something like:
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
annotations:
release.openshift.io/create-only: "true"
creationTimestamp: "2020-03-17T18:12:52Z"
generation: 1
name: cluster
resourceVersion: "1563"
selfLink: /apis/config.openshift.io/v1/oauths/cluster
uid: ebb0582d-b0e4-4c40-a33f-12459593f8e2
spec: {}
There are a few things to note here. Firstly, there's basically nothing here!
How does the kubeadmin
user work, then? The OpenShift OAuth system knows to
look for a kubeadmin
Secret in the kube-system
Namespace. You can
examine it with the following:
oc get secret -n kube-system kubeadmin -o yaml
You will see something like:
apiVersion: v1
data:
kubeadmin: JDJhJDEwJDdQNHZtbXMxdmpDa3FsNlJMLjJBcC5BSWdBazB6d09IWUdXZEdrRXBERGRwWXNmVVcxanpX
kind: Secret
metadata:
creationTimestamp: "2019-04-29T17:30:51Z"
name: kubeadmin
namespace: kube-system
resourceVersion: "2065"
selfLink: /api/v1/namespaces/kube-system/secrets/kubeadmin
uid: 892945dc-6aa4-11e9-9959-02774c6d6b2e
type: Opaque
That Secret contains the encoded hash of the kubeadmin
password. This
account will continue to work even after we configure a new OAuth
. If you
want to disable it, you would need to delete the secret.
In a real-world environment, you will likely want to integrate with your
existing identity management solution. For this lab we are configuring LDAP
as our identityProvider
. Here's an example of the OAuth configuration. Look
for the element in identityProviders
with type: LDAP
like the following:
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
name: cluster
spec:
identityProviders:
- name: ldap
challenge: false
login: true
mappingMethod: claim
type: LDAP
ldap:
attributes:
id:
- distinguishedName
email:
- userPrincipalName
name:
- givenName
preferredUsername:
- sAMAccountName
bindDN: "cn=ldapuser,cn=Users,dc=dcloud,dc=demo,dc=com"
bindPassword:
name: ldapuser-secret
insecure: true
url: "ldap://ad1.dcloud.demo.com:389/cn=Users,dc=dcloud,dc=demo,dc=com?sAMAccountName?sub?(memberOf=cn=ocp-user,cn=Users,dc=dcloud,dc=demo,dc=com)"
tokenConfig:
accessTokenMaxAgeSeconds: 86400
Some notable fields under identityProviders:
:
name
: The unique ID of the identity provider. It is possible to have multiple authentication providers in an OpenShift environment, and OpenShift is able to distinguish between them.mappingMethod: claim
: This section has to do with how usernames are assigned within an OpenShift cluster when multiple providers are configured. See the Identity provider parameters section for more information.attributes
: This section defines the LDAP fields to iterate over and assign to the fields in the OpenShift user's "account". If any attributes are not found / not populated when searching through the list, the entire authentication fails. In this case we are creating an identity that is associated with the ADdistinguishedName
, an email address from the LDAPuserPrincipalName
, a name from the LDAPgivenName
, and a username from the ADsAMAccountName
.bindDN
: When searching LDAP, bind to the server as this user.bindPassword
: Reference to the Secret that has the password to use when binding for searching.url
: Identifies the LDAP server and the search to perform.
For more information on the specific details of LDAP authentication in OpenShift you can refer to the Configuring an LDAP identity provider documentation.
To setup the LDAP identity provider we must:
- Create a
Secret
with the bind password. - Update the
cluster
OAuth
object with the LDAP identity provider.
As the kubeadmin
user apply the OAuth configuration with oc
.
oc create secret generic ldapuser-secret --from-literal=bindPassword=b1ndP^ssword -n openshift-config
cat <<EOF | oc apply -f -
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
name: cluster
spec:
identityProviders:
- name: ldap
challenge: false
login: true
mappingMethod: claim
type: LDAP
ldap:
attributes:
id:
- distinguishedName
email:
- userPrincipalName
name:
- givenName
preferredUsername:
- sAMAccountName
bindDN: "cn=ldapuser,cn=Users,dc=dcloud,dc=demo,dc=com"
bindPassword:
name: ldapuser-secret
insecure: true
url: "ldap://ad1.dcloud.demo.com:389/cn=Users,dc=dcloud,dc=demo,dc=com?sAMAccountName?sub?(memberOf=cn=ocp-user,cn=Users,dc=dcloud,dc=demo,dc=com)"
tokenConfig:
accessTokenMaxAgeSeconds: 86400
EOF
Syncing LDAP Groups to OpenShift Groups
In OpenShift, groups can be used to manage users and control permissions for
multiple users at once. There is a section in the documentation on how to
sync groups with LDAP. Syncing groups involves running a program called groupsync
when logged into OpenShift as a user with cluster-admin
privileges, and using
a configuration file that tells OpenShift what to do with the users it finds in
the various groups.
We have provided a groupsync
configuration file for you:
View configuration file
kind: LDAPSyncConfig
apiVersion: v1
url: ldap://ad1.dcloud.demo.com:389
insecure: true
bindDN: cn=ldapuser,cn=Users,dc=dcloud,dc=demo,dc=com
bindPassword: b1ndP^ssword
rfc2307:
groupsQuery:
baseDN: cn=Users,dc=dcloud,dc=demo,dc=com
derefAliases: never
filter: (cn=ocp-*)
scope: sub
pageSize: 0
groupUIDAttribute: distinguishedName
groupNameAttributes:
- cn
groupMembershipAttributes:
- member
usersQuery:
baseDN: cn=Users,dc=dcloud,dc=demo,dc=com
derefAliases: never
filter: (objectclass=user)
scope: sub
pageSize: 0
userUIDAttribute: distinguishedName
userNameAttributes:
- sAMAccountName
Without going into too much detail (you can look at the documentation), the
groupsync
config file does the following:
- searches LDAP using the specified bind user and password
- queries for any LDAP groups whocp name begins with
ocp-
- creates OpenShift groups with a name from the
cn
of the LDAP group - finds the members of the LDAP group and then puts them into the created OpenShift group
- uses the
dn
anduid
as the UID and name attributes, respectively, in OpenShift
Execute the groupsync
:
cat <<EOF > groupsync.yaml
kind: LDAPSyncConfig
apiVersion: v1
url: ldap://ad1.dcloud.demo.com:389
insecure: true
bindDN: cn=ldapuser,cn=Users,dc=dcloud,dc=demo,dc=com
bindPassword: b1ndP^ssword
rfc2307:
groupsQuery:
baseDN: cn=Users,dc=dcloud,dc=demo,dc=com
derefAliases: never
filter: (cn=ocp-*)
scope: sub
pageSize: 0
groupUIDAttribute: distinguishedName
groupNameAttributes:
- cn
groupMembershipAttributes:
- member
usersQuery:
baseDN: cn=Users,dc=dcloud,dc=demo,dc=com
derefAliases: never
filter: (objectclass=user)
scope: sub
pageSize: 0
userUIDAttribute: distinguishedName
userNameAttributes:
- sAMAccountName
EOF
oc adm groups sync --sync-config=./groupsync.yaml --confirm
You will see output like the following:
group/ocp-fancy-dev
group/ocp-user
group/ocp-normal-dev
group/ocp-teamed-app
What you are seeing is the Group objects that have been created by the
groupsync
command. If you are curious about the --confirm
flag, check the
output of the help with oc adm groups sync -h
.
If you want to see the Groups that were created, execute the following:
oc get groups
You will see output like the following:
NAME USERS
ocp-admin ldapuser
ocp-fancy-dev fancyuser1, fancyuser2
ocp-normal-dev normaluser1, teamuser1, teamuser2
ocp-teamed-app teamuser1, teamuser2
ocp-user fancyuser1, fancyuser2, normaluser1, teamuser1, teamuser2
Take a look at a specific group in YAML:
oc get group ocp-fancy-dev -o yaml
The YAML looks like:
apiVersion: user.openshift.io/v1
kind: Group
metadata:
annotations:
openshift.io/ldap.sync-time: 2020-03-11T10:57:03-0400
openshift.io/ldap.uid: cn=ocp-fancy-dev,ou=Users,o=5e615ba46b812e7da02e93b5,dc=jumpcloud,dc=com
openshift.io/ldap.url: ldap.jumpcloud.com:636
creationTimestamp: "2020-03-11T14:57:03Z"
labels:
openshift.io/ldap.host: ldap.jumpcloud.com
name: ocp-fancy-dev
resourceVersion: "48481"
selfLink: /apis/user.openshift.io/v1/groups/ocp-fancy-dev
uid: 630a9d2b-b577-46bd-8294-6b26e7f9a6e1
users:
- fancyuser1
- fancyuser2
OpenShift has automatically associated some LDAP metadata with the Group, and has listed the users who are in the group.
What happens if you list the Users?
oc get user
You will get:
No resources found.
Why would there be no Users found? They are clearly listed in the Group definition.
Users are not actually created until the first time they try to log in. What you are seeing in the Group definition is simply a placeholder telling OpenShift that, if it encounters a User with that specific ID, that it should be associated with the Group.
Change Group Policy
We will grant a cluster role cluster-admin
to ldap group ocp-admin
Change the policy for the ocp-admin
Group:
oc adm policy add-cluster-role-to-group cluster-admin ocp-admin
In your environment, there is a special group of super developers called
ocp-fancy-dev who should have special cluster-reader
privileges. This is a role
that allows a user to view administrative-level information about the cluster.
For example, they can see the list of all Projects in the cluster.
Change the policy for the ocp-fancy-dev
Group:
oc adm policy add-cluster-role-to-group cluster-reader ocp-fancy-dev
Note: If you are interested in the different roles that come with OpenShift, you can learn more about them in the role-based access control (RBAC) documentation.
Examine cluster-admin
policy
login as a ldapuser
oc login -u ldapuser -p b1ndP^ssword
Then, try to list Projects:
oc get projects
You will see a full list of projects.
Examine cluster-reader
policy
Go ahead and login as a regular user:
oc login -u normaluser1 -p openshift
Then, try to list Projects:
oc get projects
You will see:
No resources found.
Now, login as a member of ocp-fancy-dev
:
oc login -u fancyuser1 -p openshift
And then perform the same oc get projects
and you will now see the list of all
of the projects in the cluster:
NAME DISPLAY NAME STATUS
app-management
* default
kube-public
kube-system
labguide
openshift
openshift-apiserver
...
You should now be starting to understand how RBAC in OpenShift Container Platform can work.
Create Projects for Collaboration
Make sure you login as the cluster administrator:
oc login -u ldapuser
Then, create several Projects for people to collaborate:
oc adm new-project app-dev --display-name="Application Development"
oc adm new-project app-test --display-name="Application Testing"
oc adm new-project app-prod --display-name="Application Production"
You have now created several Projects that represent a typical Software Development Lifecycle setup. Next, you will configure Groups to grant collaborative access to these projects.
Note: Creating projects with oc adm new-project
does not use the project request
process or the project request template. These projects will not have quotas or
limitranges applied by default. A cluster administrator can "impersonate" other
users, so there are several options if you wanted these projects to get
quotas/limit ranges:
. use --as
to specify impersonating a regular user with oc new-project
. use oc process
and provide values for the project request template, piping
into create (eg: oc process ... | oc create -f -
). This will create all of
the objects in the project request template, which would include the quota and
limit range.
. manually create/define the quota and limit ranges after creating the projects.
For these exercises it is not important to have quotas or limit ranges on these projects.
Map Groups to Projects
As you saw earlier, there are several roles within OpenShift that are
preconfigured. When it comes to Projects, you similarly can grant view, edit,
or administrative access. Let's give our ocp-teamed-app
users access to edit the
development and testing projects:
oc adm policy add-role-to-group edit ocp-teamed-app -n app-dev
oc adm policy add-role-to-group edit ocp-teamed-app -n app-test
And then give them access to view production:
oc adm policy add-role-to-group view ocp-teamed-app -n app-prod
Now, give the ocp-fancy-dev
group edit access to the production project:
oc adm policy add-role-to-group edit ocp-fancy-dev -n app-prod
Examine Group Access
Log in as normaluser1
and see what Projects you can see:
oc login -u normaluser1 -p openshift
oc get projects
You should get:
No resources found.
Then, try teamuser1
from the ocp-teamed-app
group:
oc login -u teamuser1 -p openshift
oc get projects
You should get:
NAME DISPLAY NAME STATUS
app-dev Application Development Active
app-prod Application Production Active
app-test Application Testing Active
You did not grant the team users edit access to the production project. Go ahead
and try to create something in the production project as teamuser1
:
oc project app-prod
oc new-app docker.io/siamaksade/mapit
You will see that it will not work:
error: can't lookup images: imagestreamimports.image.openshift.io is forbidden: User "teamuser1" cannot create resource "imagestreamimports" in API group "image.openshift.io" in the namespace "app-prod"
error: local file access failed with: stat docker.io/siamaksade/mapit: no such file or directory
error: unable to locate any images in image streams, templates loaded in accessible projects, template files, local docker images with name "docker.io/siamaksade/mapit"
Argument 'docker.io/siamaksade/mapit' was classified as an image, image~source, or loaded template reference.
The 'oc new-app' command will match arguments to the following types:
1. Images tagged into image streams in the current project or the 'openshift' project
- if you don't specify a tag, we'll add ':latest'
2. Images in the Docker Hub, on remote registries, or on the local Docker engine
3. Templates in the current project or the 'openshift' project
4. Git repository URLs or local paths that point to Git repositories
--allow-missing-images can be used to point to an image that does not exist yet.
See 'oc new-app -h' for examples.
This failure is exactly what we wanted to see.
Prometheus
Now that you have a user with cluster-reader
privileges (one that can see
many administrative aspects of the cluster), we can revisit Prometheus and
attempt to log-in to it.
Login as a the user with cluster-reader
privileges:
oc login -u fancyuser1 -p openshift
Find the prometheus
Route
with the following command:
oc get route prometheus-k8s -n openshift-monitoring
You will see something like the following:
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
prometheus-k8s prometheus-k8s-openshift-monitoring.{{ ROUTE_SUBDOMAIN }} prometheus-k8s web reencrypt/Redirect None
Warning: Before continuing, make sure to go to the OpenShift web console and log out
by using the dropdown menu at the upper right where it says kube:admin
.
Otherwise Prometheus will try to use your kubeadmin
user to pass through
authentication. While it will work, it doesn't demonstrate the
cluster-reader
role.
The installer configured a Route
for Prometheus by default. Go ahead and
control+click the Prometheus link to open it in your browser. You'll be
greeted with a login screen. Click the Log in with OpenShift button, then
select the ldap
auth mechanism, and use the fancyuser1
user that you gave
cluster-reader
privileges to earlier. More specifically, the
ocp-fancy-dev
group has cluster-reader
permissions, and fancyuser1
is a
member. Remember that the password for all of these users is openshift
. You
will probably get a certificate error because of the self-signed certificate.
Make sure to accept it.
After logging in, the first time you will be presented with an auth proxy permissions acknowledgement.
There is actually an OAuth proxy that sits in the flow between you and the
Prometheus container. This proxy is used to validate your AuthenticatioN
(AuthN) as well as authorize (AuthZ) what is allowed to happen. Here you are
explicitly authorizing the permissions from your fancyuser1
account to be
used as part of accessing Prometheus. Hit Allow selected permissions.
At this point you are viewing Prometheus. There are no alerts configured. If
you look at Status
and then Targets
you can see some interesting
information about the current state of the cluster.