Each deployment of an EasyAuth Proxy is specific to:
- A single AAD tenant
- A single App Registration within that tenant, which means a single set of scopes, roles, etc.
- A single Signup/Signin policy (if using Azure AD B2C)
- A single set of EasyAuth configuration options
You may protect multiple backend applications with a single proxy if, practically speaking, you are ok with managing access to these applications as a single "logical" application. A common example of this scenario is a composite API that is served by multiple backend microservices.
For most stand-alone applications, however, you will probably elect to deploy a single EasyAuth proxy for each application
Here's a list of possible configuration options for the EasyAuth Proxy, which you can set in the values.yaml file of the helm chart or by providing an external configuration file:
Parent | Name | Usage |
---|---|---|
azureAd | instance | The Azure Ad instance that will be used to authenticate users. The default value of 'https://login.microsoftonline.com/' won't need to be changed in most cases, but you will need to provide the appropriate value if you are using a sovereign or government Azure tenant or using a custom url for Azure AD B2C. |
azureAd | domain | Optional. If your users are internal organizational accounts from a single tenant domain, this can be helpful by providing a "hint" during login to help ensure that the user logs in with the appropriate user account |
azureAd | tenantId | If you are using the setup script, this value will be determined at runtime and filled in for you. Otherwise, this is the GUID tenant identifier for the Azure AD tenant you want to use. See How to find my tenant id |
azureAd | clientId | If you are using the setup script, this value will be determined at runtime and filled in for you. Otherwise, this is the GUID application identifier for the Azure AD app registration you want to use. See App Registrations |
azureAd | callbackPath | The path that Open Id Connect messages will be returned from Azure AD. In the majority of cases, you should never need to change this. See Advanced Scenarios |
azureAd | signedOutCallbackPath | Reserved for future use - Not currently used |
azureAd | signUpSignInPolicyId | For B2C only. This is the name of the policy that should be used. Otherwise, leave blank. |
azureAd | clientSecretKeyRefName, clientSecretKeyRefKey | Secret container and key for the client secret. Do not change these or set them directly or store the secret in a yaml file. Rather, provide your secret to helm via the command line via --set secret.azureclientsecret=$CLIENT_SECRET |
easyAuthForK8s | dataProtectionFileLocation | data protection key ring location. |
easyAuthForK8s | signinPath | The path that the proxy host will respond to sign-in requests. The default should not need to be changed, except for in Advanced Scenarios. Note that when changing this value, you must also update the nginx.ingress.kubernetes.io/auth-signin annotation in your ingresses to match. |
easyAuthForK8s | authPath | The path that the proxy host will respond to auth requests. The default should not need to be changed, except for in Advanced Scenarios. Note that when changing this value, you must also update the nginx.ingress.kubernetes.io/auth-url annotation in your ingresses to match. |
easyAuthForK8s | allowBearerToken | Default is "false". If "true" this will allow bearer tokens to be used in addition to cookies. Primarily for API callers. |
easyAuthForK8s | defaultRedirectAfterSignin | This is the final fallback url that the user will be routed to after succesfully logging in. Depending on your nginx configuration, the primary redirect preference will be the path provided by the "rd" query parameter, followed by the url that the user was originally trying to access. This option provides a tertiary and final fallback, with "/" being the default |
easyAuthForK8s | compressCookieClaims | Option is "true" by default, set "false" to disable. Experimental feature that serializes, compresses, and encodes the payload of non-essential claims to keep the cookie size as small as possible. This helps to avoid increasing the nginx header buffers beyond the default settings and reduces the size of the data sent from the client with each request. WARNING!: This feature may introduce a security vulnerability, although no specific vulnerability is known at this time. CRIME, a well-known exploit, takes advantage of compressed streams to decrypt data, however it requires the attacker to be able to introduce arbitrary data into the stream and observe its compressed state. For this feature we are only compressing a portion of the payload which an attacker should not be able to manipulate, so it should be safe in theory. To mitigate any potential concerns, avoid sending sensitive data to the back-end service, or disable this feature. |
easyAuthForK8s | responseHeaderPrefix | Prefix for all user information headers. Default is "x-injected-". There is no reason to change this unless you have multiple EasyAuth proxies protecting the same backend and need to discern the source of the headers. |
easyAuthForK8s | claimEncodingMethod | Default is UrlEncode, which should work for most situations. Valid values are:
|
easyAuthForK8s | headerFormatOption | How headers should be packaged. Default is Separate. Note that regardless of the option you choose, only headers defined in the nginx.ingress.kubernetes.io/auth-response-headers ingress annotation will be sent to the back end.
|
Each kubernetes you configure should generally be in the form of:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: easyauth-sample-ingress-default
annotations:
nginx.ingress.kubernetes.io/auth-url: "https://$host/easyauth/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/easyauth/login"
nginx.ingress.kubernetes.io/auth-response-headers: "x-injected-userinfo,x-injected-name,x-injected-oid,x-injected-preferred-username,x-injected-sub,x-injected-tid,x-injected-email,x-injected-groups,x-injected-scp,x-injected-roles,x-injected-graph"
cert-manager.io/cluster-issuer: letsencrypt-prod
Except for advanced scenarios, you don't need to change any of these values. You can, however, extend the behavior of EasyAuth by adding parameters to the auth-url
. For several examples of this, see sample-ingress.yaml
Roles are a common way to define a group of users that have their own set of permissions. For example, if your application has a page that's only for administrators and not normal users, you can define an application role in Azure AD, and create an ingress requiring that role for the page. To do this, add a role
query parameter to the nginx.ingress.kubernetes.io/auth-url
. You can request multiple roles or combinations of roles by using a pipe delimiter (role=A|B
-- must have role A or role B) or multiple role
parameters (role=A&role=B
=> must have role A and role B).
For example:
nginx.ingress.kubernetes.io/auth-url: "https://$host/easyauth/auth?role=A|B&role=C"
reads as:
"requires role (A OR B) AND role C"
One thing to be aware that is unique to roles (versus scopes below), when a token is requested from Azure AD the token will contain all of the roles that the user is assigned to. So in the example above, if the user only has role "A" and not "C" EasyAuth will present them with an "Access Denied" error page. This is because roles (which are assigned) are pre-determined, whereas scopes (which are consented to) can be appended during the log in process.
Scopes behave similar to roles, by using the scope
query parameter. The main difference is that a user can consent to additional scopes at run time, so if the auth-url
requires a scope the user does not currently have, they will be redirected back to Azure AD to acquire the scope. Note that if you are using graph queries (below), you must also request the corresponding graph scopes required by the query. More on that below.
EasyAuth has the ability to query the Microsoft Graph to get additional information about the user. This can be great for providing additional data beyond what would normally be provided in the id token. However, there are some limitations to be aware of:
- Graph queries only work with cookie authentication, since cookies are used to store that user data. Bearer tokens are limited to the data that's actually in the token itself.
- Graph queries add additional overhead. For that reason, queries are only run one -- when the user logs in. The data remains static from that point until the user logs in again.
- Data returned from queries can get quite large if you aren't careful. It must then be encoded and encrypted, which makes it even larger. This can cause problems with header sizes in the ingress controller, as well as increase latency as the client must return the cookie with each request. To mitigate this, Cookie Compression is turned on by default. In addition, it is strongly recommended that you limit the fields returned by the query to fields that you actually will use by using $select and $filter.
To add graph query results to your configuration, update the appropriate ingress annotations to include the 'graph' parameter:
nginx.ingress.kubernetes.io/auth-url: "https://$host/easyauth/auth?scope=User.Read&graph=/me?$select=displayName,jobTitle"
Notes:
- The example includes the request for the Graph scope "User.Read", to ensure that the query has permission to run. If the user has not previously consented to this scope, they will be prompted to do so during the log in process.
- You only need to provide the relative url of the query itself. The graph host and API version are inferred from the discovery process.
- You may include multiple
graph
query parameters (?graph=foo&graph=bar
) to return multiple result sets. The results will be returned in the order they appear in the query string - The example above shows the query text in its original form, but its a good idea to always url encode parameter values. For example,
/me?$select=displayName,jobTitle
becomes%2Fme%3F%24select%3DdisplayName%2CjobTitle
. - The resulting
x-injected-graph
header from the sample will look like:[{"displayName": "Some User","jobTitle": "Some Title"}]
- Not all graph queries work with all types of users, since many graph resources are dependent on the various product licenses that are assigned to the user. If a query raises errors, an
error
property will be returned along with a message. - Finally, graph queries are run against the Azure AD tenant that EasyAuth is configured to use, which is not necessarily a particular user's home tenant. For example, let's say EasyAuth is configured to use the "Contoso" tenant, which contains a B2B Guest user from the "Fabrikam" tenant. You utilize a graph query that looks for groups users belong to. In this case the results returned for the B2B user will be their "Contoso" group memberships, not groups they belong to in their home "Fabrikam" tenant.