Many organizations today are using Azure Active Directory (Azure AD) to manage authentication and authorization for their users. Kasten by Veeam customers often ask if we support authentication/authorization with Azure AD. The short answer is yes, and it’s very simple to set it up. You can also use the Azure AD group to manage authorization in Kasten K10.
The long answer is that Kasten K10 supports many authentication schemes (Basic authorization, token authorization, oAuth, and so on) as well as OIDC, because it’s one of the most popular authentication schemes. Azure AD also lets users authenticate with a variety of protocols, including OIDC. The Azure groups are populated in a JWT token, and Kasten K10 uses these groups in the Kubernetes impersonation headers. This enables the creation of a Role Binding with a group in Kubernetes to define authorization on Kasten K10s API.
That was a long answer indeed, and if you don’t understand it completely, don’t worry! We’re going to break it down.
What is OIDC, and how do Kasten K10 and Azure AD fit in?
OIDC is built on top of oAuth, which lets a web service act on behalf of a user. A popular action is providing identity, which is sent in a JWT token. A JWT token is another technology based on digital signatures that allows an application to validate that a token has been issued by an organization:
We can update this diagram to include Kasten K10 and Azure AD:
In the (8) message we have a JWT Token sent by Azure AD:
Header
{
"typ": "JWT",
"alg": "RS256",
"kid": "nOo3ZDrODXEK1jKWhXslHR_KXEg"
}
Payload
{
"aud": "3cae7658-5192-4122-b31a-1efcb9355a6f",
"iss": "https://login.microsoftonline.com/6d2374b4-aceb-42ac-966a-716a93f07db0/v2.0",
"iat": 1626773517,
"nbf": 1626773517,
"exp": 1626777417,
"aio": "ATQAy/8TAAAAHmjuDRKO8auz1LBInhIdKq6FVAzw0PqdV7BzqdxwVyHnk+euyZhD0A9/pnMzt+oR",
"c_hash": "fEsoqHMSZ1OvGRwI6hJP6g",
"groups": [
"a318b1eb-8b78-4715-98ad-ffc8670ac79d"
],
"name": "Michael Courcy",
"nonce": "d8l9s4gpgxb",
"oid": "f4b232e2-f4f3-43cf-8fff-657668223564",
"preferred_username": "michael@kastenio.onmicrosoft.com",
"rh": "0.AS4AtHQjbeusrEKWanFqk_B9sFh2rjySUSJBsxoe_Lk1Wm8uAFQ.",
"sub": "A5s2xvvBedaSwGVN7B3YBYKLIdabfCpURUrnItSEjwQ",
"tid": "6d2374b4-aceb-42ac-966a-716a93f07db0",
"uti": "H_vg9nlY9kaJ50fe8u3eAQ",
"ver": "2.0"
}
The groups value is an Azure ID:
According to Microsoft, the sub ID is:
“The principal about which the token asserts information, such as the user of an app. This value is immutable and cannot be reassigned or reused. It can be used to perform authorization checks safely. The subject is, however, a pairwise identifier – it is unique to a particular application ID. Therefore, if a single user signs into two different apps using two different client IDs, those apps will receive two different values for the subject claim. This may or may not be desired depending on your architecture and privacy requirements. See also the oid claim (which does remain the same across apps within a tenant).”
Indeed, the oID corresponds to the ID of the user in Azure:
The groups and sub (subject) will be prefixed and added to the subject access review made by the Kasten K10 dashboard to the Kubernetes API.
You can see it in your /k10/#/settings/support page in kasten dashboard:
Here, I chose to prefix sub and groups with “michael_azure,” but you can change this value.
The username and groups will be used to build the subject access review when the dashboard requests the Kubernetes API. That’s why the rolebinding to the group is in my cluster:
michael_azure_a318b1eb-8b78-4715-98ad-ffc8670ac79d
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: k10-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: k10-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: michael_azure_a318b1eb-8b78-4715-98ad-ffc8670ac79d
Anyone belonging to this Azure group will have a Kasten K10 admin role.
Configuring a Kasten K10 application in Azure AD
How to create a relying party (client) in Azure AD
Kasten K10 is the relying party in this process and needs to be created in Azure AD.
If you haven’t already, create an app registration to serve as the relying party inside Azure:
This application will have a client ID and a client secret. The relying party (in this case Kasten K10) must provide these two pieces of information when interacting with the ID Provider (in this case Azure AD), as shown in the diagram.
It’s possible to create a new secret, if needed. Azure AD allows clients to have multiple secrets.
Configuring the application (client) for web authentication
The goal of this application is to ensure web authentication. We have to state the goal explicitly, and you must provide the list of redirects URLs allowed (that correspond to (6) in the diagram).
This is very important, because it’s used to pass the authorization code from the user to the relying party. You may note that we use two URLs in the example:
- https://kasten.michael.dev.azure.kasten.io/k10/auth-svc/v0/oidc/redirect
- https://oidcdebugger.com/debug
The first one is the URL to Kasten K10 At this address, Kasten K10 will pick up the authorization code and obtain the JWT token, but you often need to understand what’s included in the JWT Token, which Kasten K10 does not provide, even in debug mode. The debugger tool (https://oidcdebugger.com/debug) enables you to see the content of your JWT token:
Adding the groups to the token
By default, Azure AD does not include the groups information in the JWT token. You have to configure it explicitly in the token configuration menu:
I chose to include the security groups, because that made the most sense in this case. Including office 365 groups here does not make sense from an authorization perspective, because my account belongs to only two groups (I’m not a AAD DC Administrator).
The JWT token only contains one group with the ID of the security group to which I belong:
Testing and checking the JWT token content
Now that we’ve finished configuring Azure AD, before configuring Kasten K10, we must check the content of the JWT Token that Azure will send us.
Go to https://oidcdebugger.com/debug to configure your test:
#1 in the OpenID Connect image above, can be obtained in the endpoints panel of your app:
#2 in the OpenID Connect image above, is your client ID that we already noted in the previous steps:
#3 in the OpenID Connect image above, is the list of OIDC scopes the client request to Azure AD (an OIDC scope is defining the group of information you want to obtain for the user from the ID Provider).
Choose the code, ID token and send request:
You should get something similar to this:
Configuring Kasten for using Azure AD
Now that we successfully obtained a JWT token with groups inside to manage authorization, we are ready to configure our helm values for installing or upgrading Kasten K10. I will display only relevant values for the connection with Azure AD OIDC.
If you have already installed Kasten K10, you can create a values.yaml file from your helm install:
helm get values k10 -n kasten-io > values.yaml
Then, complete it with this OIDC information:
auth:
oidcAuth:
clientID: 3cae7658-5192-4122-b31a-1efcb9355a6f
clientSecret: xxxxxxxxxxxxxxxxxxxxxxx
enabled: true
groupClaim: groups
groupPrefix: michael_azure_
prompt: select_account
providerURL: https://login.microsoftonline.com/6d2374b4-aceb-42ac-966a-716a93f07db0/v2.0
redirectURL: https://kasten.michael.dev.azure.kasten.io/
scopes: openid email
usernameClaim: sub
usernamePrefix: michael_azure_
All the oidcAuth options are described here. The provider URL can be obtained through the well-known endpoint:
curl
https://login.microsoftonline.com/6d2374b4-aceb-42ac-966a-716a93f07db0/v2.0/.well-known/openid-configuration | jq '.issuer'
"https://login.microsoftonline.com/6d2374b4-aceb-42ac-966a-716a93f07db0/v2.0"
Now update or create your Kasten K10 install:
helm upgrade k10 kasten/k10 -n kasten-io -f values.yaml
If everything executes the way it’s supposed to, you should:
- Be redirected when trying to log in
- See your username and groups prefixed with usernamePrefix and groupPrefix
We’re almost done!
Now that we have the group michael_azure_a318b1eb-8b78-4715-98ad-ffc8670ac79d included in each subject access review that Kasten K10 executes against the Kubernetes API, we can create an appropriate rolebinding with this group.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: k10-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: k10-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: michael_azure_a318b1eb-8b78-4715-98ad-ffc8670ac79d
This rolebinding will give any member of the Azure group a318b1eb-8b78-4715-98ad-ffc8670ac79d the role of Kasten K10 admin.
To explicitly split the Kubernetes admin role and the Kasten K10 admin role, the Kasten K10 admin ClusterRole does not include any authorization on secret or deployment, which is needed to work with the dashboard. It’s why if your user does not have this authorization, you also have to create a rolebinding limited to the kasten-io namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: k10-admin
namespace: k10-ns-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: k10-ns-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: michael_azure_a318b1eb-8b78-4715-98ad-ffc8670ac79d
Of course, a more sophisticated scenario could be imagined with multiple groups and the list of available built-in roles created by Kasten K10 at install, or a role that you tailor yourself.
Conclusion
This tutorial shows how you can integrate authentication and authorization in Kasten K10 with Azure AD, thanks to our native support for OIDC. This tutorial can be reapplied with little adaptation to any OIDC provider such as Okta, Ping Identity, Google Identity, Git Lab and so on. Nearly all big players support OIDC.
If you need to connect using an active directory (not Azure AD) or OpenShift we also integrate the DEX component. Dex will act as an OIDC provider and will hand off the connections to the non-OIDC provider. A complete example with OpenShift is described here.