Skip to content

Add Azure AD use case #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
./uaa-4.24.0/
conf/asymmetric_key/uaa.yml
conf/symmetric_key/uaa.yml
conf/azure/*
!conf/azure/rabbitmq.config
plugin
rabbitmq-auth-backend-oauth2-*
master-*.zip
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ start-uaa: ## Start uaa (remember to run make build-uaa if you have not done )
start-keycloak: ## Start keycloak
@./bin/keycloak/deploy

build-azure: ## Generate SSL files for Azure AD
@./bin/azure/deploy

build-uaa: ## Build uaa image
@(cd uaa-latest; make build-uaa; cd ..)

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ If you want to understand the details of how to configure RabbitMQ with Oauth2 g
- Use different OAuth 2.0 servers
- [KeyCloak](use-cases/keycloak.md)
- [https://auth0.com/](use-cases/oauth0.md)
- [Azure Active Directory](use-cases/azure.md)

- [Understand the environment](#understand-the-environment)
- [RabbitMQ server](#rabbitmq-server)
Expand Down
Binary file added assets/azure-ad-enterprise-application.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/azure-ad-jwks-uri.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/azure-ad-oauth-registered-app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions bin/azure/deploy
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env bash

SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

ROOT=$SCRIPT/../..

echo "Generate SSL Certificate and Key for localhost"
echo "--------------------------------"
echo "Generate root key"
echo "--------------------------------"
openssl genrsa 2048 > ${ROOT}/conf/azure/rabbitmq-ca.key
echo ""
echo "--------------------------------"
echo "Create and self-sign root certificate"
echo "--------------------------------"
openssl req -new -x509 -nodes -days 365 \
-key ${ROOT}/conf/azure/rabbitmq-ca.key \
-out ${ROOT}/conf/azure/rabbitmq-ca.crt \
-subj "/C=US/ST=California/L=San Francisco/O=RabbitMQ/OU=OAuth 2.0 Tutorial/CN=RootCA"
echo ""
echo "--------------------------------"
echo "Create Certificate Signing Request and associated private key for localhost"
echo "--------------------------------"
openssl req -newkey rsa:2048 -nodes \
-keyout ${ROOT}/conf/azure/rabbitmq.key \
-out ${ROOT}/conf/azure/rabbitmq.csr \
-subj "/C=US/ST=California/L=San Francisco/O=RabbitMQ/OU=OAuth 2.0 Tutorial/CN=localhost"
echo ""
echo "--------------------------------"
echo "Create certificate for localhost"
echo "--------------------------------"
openssl x509 -req -days 365 \
-in ${ROOT}/conf/azure/rabbitmq.csr \
-out ${ROOT}/conf/azure/rabbitmq.crt \
-CA ${ROOT}/conf/azure/rabbitmq-ca.crt \
-CAkey ${ROOT}/conf/azure/rabbitmq-ca.key \
-CAcreateserial
echo ""
echo "--------------------------------"
echo "Configure SSL cert/key ownership"
echo "--------------------------------"
chown 999:999 ${ROOT}/conf/azure/rabbitmq-ca.crt \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I run it on my mac, these two lines failed. I skipped them and everything worked fine. @baptistedaroit Do we need them?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MarcialRosales I think it depends on how docker is configured on the machine. In my case, I needed it because the key was mounted in the container with root as owner, with permissions 600 thus preventing rabbitmq to read it at startup.

${ROOT}/conf/azure/rabbitmq.crt \
${ROOT}/conf/azure/rabbitmq-ca.key

15 changes: 11 additions & 4 deletions bin/deploy-rabbit
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ CONFIG=${CONFIG:-rabbitmq.config}
IMAGE_TAG=${IMAGE_TAG:-3.10.0-rc.6-management}
IMAGE=${IMAGE:-rabbitmq}

if [ "${MODE}" == "azure" ]; then
EXTRA_PORTS="-p 15671:15671"
EXTRA_MOUNTS="-v $SCRIPT/../conf/${MODE}/rabbitmq-ca.crt:/etc/rabbitmq/rabbitmq-ca.crt \
-v $SCRIPT/../conf/${MODE}/rabbitmq.key:/etc/rabbitmq/rabbitmq.key \
-v $SCRIPT/../conf/${MODE}/rabbitmq.crt:/etc/rabbitmq/rabbitmq.crt"
fi

docker network inspect rabbitmq_net >/dev/null 2>&1 || docker network create rabbitmq_net
docker rm -f rabbitmq 2>/dev/null || echo "rabbitmq was not running"
echo "running RabbitMQ with mode $MODE"
docker run -d --name rabbitmq --net rabbitmq_net \
-p 15672:15672 -p 5672:5672 \
-v $SCRIPT/../conf/${MODE}/${CONFIG}:/etc/rabbitmq/rabbitmq.config:ro \
-v $SCRIPT/../conf/enabled_plugins:/etc/rabbitmq/enabled_plugins \
-v $SCRIPT/../conf:/conf ${IMAGE}:${IMAGE_TAG}
-p 15672:15672 -p 5672:5672 ${EXTRA_PORTS}\
-v ${SCRIPT}/../conf/${MODE}/${CONFIG}:/etc/rabbitmq/rabbitmq.config:ro \
-v ${SCRIPT}/../conf/enabled_plugins:/etc/rabbitmq/enabled_plugins \
-v ${SCRIPT}/../conf:/conf ${EXTRA_MOUNTS} ${IMAGE}:${IMAGE_TAG}
35 changes: 35 additions & 0 deletions conf/azure/rabbitmq.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[
{rabbit, [
{auth_backends, [rabbit_auth_backend_oauth2, rabbit_auth_backend_internal]}
]},
{rabbitmq_management, [
{listener, [{port, 15671},
{ssl, true},
{ssl_opts, [{cacertfile, "/etc/rabbitmq/rabbitmq-ca.crt"},
{certfile, "/etc/rabbitmq/rabbitmq.crt"},
{keyfile, "/etc/rabbitmq/rabbitmq.key"},

%% don't do peer verification to HTTPS clients
{verify, verify_none},
{fail_if_no_peer_cert, false},

{client_renegotiation, false},
{secure_renegotiate, true},
{honor_ecc_order, true},
{honor_cipher_order, true}
]}
]},
{oauth_enable, true},
{oauth_client_id, "PUT YOUR AZURE AD APPLICATION ID"},
{oauth_client_secret, "PUT YOUR AZURE AD APPLICATION SECRET"},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a mistake from the beginning even though in your instructions you cleared set, "take the value of the secret". And I wrongly took the secret id. Maybe, and given in the Azure user interface it is referred as "secret value", we can use "PUT YOUR AZURE AD APPLICATION SECRET VALUE"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahah yep you are right, it can be confusing. Sorry about that one!

{oauth_provider_url, "https://login.microsoftonline.com/AZURE_AD_TENANT_ID"}

]},
{rabbitmq_auth_backend_oauth2, [
{resource_server_id, <<"PUT YOUR AZURE AD APPLICATION ID">>},
{extra_scopes_source, <<"roles">>},
{key_config, [
{jwks_url, <<"PUT YOUR AZURE AD JWKS URI VALUE">>}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Umm. I think I should initialize jwks_url from the openconnect discovery endpoint unless the discover endpoint does not return a jwks_uri. I did not think about this one. Thank you !!!

]}
]}
].
240 changes: 240 additions & 0 deletions use-cases/azure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
# Use Azure Active Directory (Azure AD) as OAuth 2.0 server

We are going to test 3 OAuth flows:
1. Access management ui via a browser :ballot_box_with_check:
2. Access management rest api :construction:
3. Access AMQP protocol :construction:

## Prerequisites to follow this guide

- Have an account in https://portal.azure.com.
- Docker
- Openssl

## Register your app

When using **Azure AD as OAuth 2.0 server**, your client app (in our case RabbitMQ) needs a way to trust the security tokens issued to it by the **Microsoft identity platform**. The first step in establishing that trust is by **registering your app** with the identity platform in Azure AD.

> :blue_book: More details about App registration in Azure AD are available [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app)

Once you have logged onto your account in [Azure Portal](https://portal.azure.com), go to **Azure Active Directory** (use the search bar if you are not able to easily find it).

In the left-hand navigation menu, click on **App Registrations**. Then, select **New registration**.

In the **Register an application** pane, provide the following informations:

- **Name**: the name you would like to give to your application (ex: *rabbitmq-oauth2*)
- **Supported Account Types**: select **Accounts in this organizational directory only (Default Directory only - Single tenant)** (you can choose other options if you want to enlarge the audience of your app)
- **Redirect URI**:
- On the **Select a platform** drop-down list, select **Single-page application (SPA)**
- Configure the **Redirect URI** to: `https://localhost:15671/js/oidc-oauth/login-callback.html`

> :warning: **IMPORTANT**: As you may have noticed, Azure AD only allows `https` links as **Redirect URI**. To fit this need, we will enable HTTPS for RabbitMQ Management UI, on port `15671`.

Click on **Register**.

![Azure AD OAuth2 App](../assets/azure-ad-oauth-registered-app.png)

Note the following values, as we will need it later to configure the `rabbitmq_auth_backend_oauth2` on RabbitMQ side:
- Directory (tenant ID)
- Application (client) ID

Click on the **Endpoints** tab and, on the right pane that has just opened, copy the value of **OpenID Connect metadata document** (ex: `https://login.microsoftonline.com/{TENANT_ID}/v2.0/.well-known/openid-configuration`) and open it in your browser.

Note the value of the `jwks_uri` key (ex: `https://login.microsoftonline.com/{TENANT_ID}/discovery/v2.0/keys`), as you will also need it later to configure the `rabbitmq_auth_backend_oauth2` on RabbitMQ side

![Azure AD JWKS URI](../assets/azure-ad-jwks-uri.png)

## Create a secret for your app

Your application needs a **client secret** to prove its identity when requesting a token.

Still on the **App registrations** page, in the left-hand menu, click on **Certificates & Secrets**, then select the **Client secrets** tab.

In the **Certificates & Secrets** pane, click on **New Client Secret** and, on the right pane that has just opened, enter a description for the secret and choose an expiration time.

Click on **Add**.

> :warning: **IMPORTANT**: Immediately note the value of the secret (as you won't be able to get it later and we will need it to configure the `rabbitmq_auth_backend_oauth2` on RabbitMQ side)

## Create OAuth 2.0 roles for your app

App roles are defined by using the [Azure portal](https://portal.azure.com) during the app registration process. When a user signs in to your application, Azure AD emits a `roles` claim for each role that the user or service principal has been granted (we will have a look at it at the end of this tutorial).

> :blue_book: More details about roles in Azure AD are available [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps)

Still in [Azure Portal](https://portal.azure.com), go back to **Azure Active Directory** home page. In the left-hand menu, click on **App Registrations** and then click on your **application name** to open your application **Overview** pane.

### Create a role to allow access to Management UI

In the left-hand menu, click on **App Roles**. Then, click on **Create App Role** to create an OAuth 2.0 role that will be used to give access to the RabbitMQ Management UI.

> :blue_book: More details about how permissions are managed on RabbitMQ when using OAuth2 are available [here](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial#about-permissions).

On the right menu that has just opened, provide the requested information:

- **Display Name**: the name you want to give to the role (ex: *Management UI Admin*)
- **Allowed member types**: Both (Users/Groups + Applications)
- **Value**: `Application_ID.tag:administrator` (where *Application_ID* is the value of the *Application (client) ID* noted earlier in this tutorial)
- **Description**: briefly describe what this role aims to (here just to give admin access to the RabbitMQ Management UI)
- **Do you want to enable this app role**: `yes` (check the box)

Click on **Apply**.

### Create a role to grant configure permission on all resources

Click again on **Create App Role**. We are now going to create an OAuth 2.0 role that will be used to give configure access to all the resources on all the RabbitMQ vhosts.

On the right menu that has just opened, fill the form as below:

- **Display Name**: the name you want to give to the role (ex: *Configure All Vhosts*)
- **Allowed member types**: Both (Users/Groups + Applications)
- **Value**: `Application_ID.configure:*/*` (where *Application_ID* is the value of the *Application (client) ID* noted earlier in this tutorial)
- **Description**: briefly describe what this role aims to (here to give permissions to configure all resources on all the vhosts available on the RabbitMQ instance)
- **Do you want to enable this app role**: `yes` (check the box)

Click on **Apply**.

## Assign App Roles to users

Now that some roles have been created for your application, you still need to assign these to some users.

Still in [Azure Portal](https://portal.azure.com), go back to **Azure Active Directory** home page and, in the left-hand menu, click on **Enterprise Applications**.

In the new left-hand menu, select **Manage -> All applications**. Use the **Search Bar** and/or the available filters to find your application.

![Azure AD Enterprise Applications](../assets/azure-ad-enterprise-application.png)

Click on the application you just created, for which you want to assign roles to users/groups, then, in the left-hand navigation menu, Select **Manage -> Users and groups**.

Click on **Add user/group** to open the **Add Assignment** pane.

Below **Users**, click on *None Selected* and, on the **Users** pane that has just opened on the right, search and select the users/groups you want to assign roles to.

Once you've selected users and groups, click on the **Select** button.

Back to the **Add assignment** pane, below **Select a Role**, click on *None Selected* and, on the **Select a role** pane that has just opened on the right, search and select the role you want to assign to the selected users.

> :bulb: If only one role is available for your application, it would be automatically selected and greyed by default

Choose a role (only a single role can be selected at a time), click on the **Select** button, and click on the **Assign** button to finalize the assignment of users and groups to the app.

:repeat: Repeat the operations for all the roles you want to assign.

## Configure RabbitMQ to use Azure AD as OAuth 2.0 authentication backend

The configuration on Azure side is done. You now have to configure RabbitMQ to use the resources you just created.

[rabbitmq.config](../conf/azure/rabbitmq.config) is a sample RabbitMQ advanced configuration to **enable Azure AD as OAuth 2.0 authentication backend** for the RabbitMQ Management UI.

Update it with the following values (you should have noted these in the previous steps):
- **Tenant ID** associated to the app that we registered in Azure AD
- **Application ID** associated to the app that we registered in Azure AD
- Value of the **secret** we created for our app in Azure AD
- Value of the **jwks_uri** key from `https://login.microsoftonline.com/{TENANT_ID}/v2.0/.well-known/openid-configuration`

```
$ vi rabbitmq.config
[
{rabbit, [
{auth_backends, [rabbit_auth_backend_oauth2, rabbit_auth_backend_internal]}
]},
{rabbitmq_management, [
{oauth_enable, true},
{oauth_client_id, "PUT YOUR AZURE AD APPLICATION ID"},
{oauth_client_secret, "PUT YOUR AZURE AD APPLICATION SECRET"},
{oauth_provider_url, "https://login.microsoftonline.com/AZURE_AD_TENANT_ID"}
]},
{rabbitmq_auth_backend_oauth2, [
{resource_server_id, <<"PUT YOUR AZURE AD APPLICATION ID">>},
{extra_scopes_source, <<"roles">>},
{key_config, [
{jwks_url, <<"PUT YOUR AZURE AD JWKS URI VALUE">>}
]}
]}
].
```

> :warning: Please update the file available in this tutorial ([here](../conf/azure/rabbitmq.config)), as it will be automatically loaded in the RabbitMQ instance that we are going to deploy later in this tutorial

### Generate SSL certificate and key
> :warning: Remember when you have registered your app on Azure AD that it only allows **https** protocol for OAuth2 **Redirect URI**? We will thus need to enable HTTPS for RabbitMQ Management UI amd its underlying API.

For the purpose of this tutorial, we can generate a self-signed certificate/key pair.

Run the following command (depending on your config, you may have to be root):
```
make build-azure
```

This generates the following files in `conf/azure`:
- **rabbitmq-ca.**crt**: a custom certificate authority that is used to generate and sign a self signed certificate for RabbitMQ
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you have an extra double * in front of crt.

- **rabbitmq.crt**: a self-signed certificate (cn=localhost)
- **rabbitmq.key**: the private key associated to the `rabbitmq.crt` certificate

:arrow_right: These files will be mounted into the `rabbitmq` docker container in the next steps of this tutorial, where they will be used to configure HTTPS for the RabbitMQ Management UI/API

## Start RabbitMQ

Run the following commands to run RabbitMQ docker image with the latest changes from `oidc-integration` branch with commit tag `69a4159f3482e5212d364f499b2ca2e05bede0ca`.

> :bulb: All the commits associated to `oidc_integration` branch are available [here](https://github.com/rabbitmq/rabbitmq-server/commits/oidc-integration). Don't hesitate to have a look a it to get the very last commit, as the one advertised in this tutorial may not stay the last one forever!

```
export IMAGE_TAG=69a4159f3482e5212d364f499b2ca2e05bede0ca-otp-min
export IMAGE=pivotalrabbitmq/rabbitmq
export MODE=azure
make start-rabbitmq
```
:arrow_right: This starts a docker container named `rabbitmq`, with RabbitMQ Management UI/API with HTTPS enabled, and configured to use your Azure AD as OAuth2 Authentication Backend, based on the information you provided in `rabbitmq.config` in the previsous steps of this tutorial.

## Verify RabbitMQ Management UI access

Go to RabbitMQ Management UI `https://localhost:15671`. Depending on your browser, ignore the security warnings (raised by the fact that we are using a self-signed certificate) to proceed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very minor: I would not wrap the uri https://localhost:15671 in single quotes so that the reader can simply click and redirect to the management ui.


Once on the RabbitMQ Management UI page, click on the **Click here to log in** button,
authenticate with your **Azure AD user**. The first time, you are likely going to have to give your
consent (it depends on the policies applied to Azure AD on your side).

> :warning: At first login, you may face the `AADSTS90008` error: just click on **Click here to log in** button
again and it will disappear (this issue seems to be known, as illustrated [here](https://docs.microsoft.com/en-us/answers/questions/671457/after-34accept34-on-consent-prompt-on-azure-sso-lo.html#answer-893848))

At the end, you should be redirected back to the RabbitMQ Management UI.

Azure AD issues an access token like this one below. The permissions are managed in the `roles` claim.
We have configured RabbitMQ with `{extra_scopes_source, <<"roles">>},` which means RabbitMQ uses
the scopes in the `roles` claim to define permissions for a logged-in user.

```
{
"aud": "30b61ef8-72d7-4e40-88f2-6e16c8d3fd88",
"iss": "https://sts.windows.net/1ffc6121-590e-4aa5-bf47-c348674069cb/",
"iat": 1655740039,
"nbf": 1655740039,
"exp": 1655744211,
"acr": "1",
"aio": "AUQAu/8TAAAAjvwucwL4nZe83vNZvg6A7sAPscI9zsGvRs8EuT7aVhubpmhRnxJ+X7nbkISoP5eBBMxoi2yiCclnH2Ocjjzsqw==",
"amr": [
"wia"
],
"appid": "30b61ef8-72d7-4e40-88f2-6e16c8d3fd88",
"appidacr": "1",
"email": "baptiste.daroit@company.com",
"idp": "https://sts.windows.net/b3f4f7c2-72ce-4192-aba4-d6c7719b5766/",
"in_corp": "true",
"ipaddr": "xxx.xxx.xxx.xxx",
"name": "Baptiste DA ROIT",
"oid": "cf2df3b4-03df-4e1e-b5c0-f232932aaead",
"rh": "0.AR8AgCG80x7L90C1mhVBBXQzQjgoklctsdBMtgYVWFwc4tgfAMQ.",
"roles": [
"30b61ef8-72d7-4e40-88f2-6e16c8d3fd88.tag:monitoring",
"30b61ef8-72d7-4e40-88f2-6e16c8d3fd88.configure:*/*"
],
"scp": "User.Read",
"sub": "6aBzW3a1FOTTrnlZEuC1SmwG0sRjVgQU49DvrYK6Rqg",
"tid": "1ffc6121-590e-4aa5-bf47-c348674069cb",
"unique_name": "baptiste.daroit@company.com",
"uti": "QHqwThTqQEK9iMdnRuD_AA",
"ver": "1.0"
}
```