iControl REST Fine-Grained Role Based Access Control
Introduction
F5's role based access control (RBAC) mechanism allows a BIG-IP administrator to assign appropriate access privileges to the users (see Manual Chapter: User Roles). For example, with the
operator
role, the user is specifically allowed to enable or disable nodes and pool members. The mechanism is generally the best way to manage users easily and consistently, however, finer access management may be required from time to time: e.g., allow only to view the stats of a predefined set of virtuals. Restricting access is especially important in iControl REST because users can remotely and directly access the system.
The existing roles and their access permissions are defined in
/mgmt/shared/authz/roles
and /mgmt/shared/authz/resource-groups
. You can add custom roles with custom permissions for particular users to these resources (iControl REST endpoints). The resources are described in BIG-IQ Systems REST API References, however, they are not exactly easy to follow. To fill the gap, this article describes a method to configure users and roles in a much finer manner.
Note
This method is only applicable to iControl REST: It does not apply to Configuration Utility or ssh.
The method relies on the resources for local users (i.e.,
/mgmt/tm/auth/user
and /mgmt/shared/authz/users
). It does not work for remote authentication mechanisms such as RADIUS or Active Directory.
Setup
In this example, a local user "foo" and a custom role "testRole" are created. The role allows users to
GET
(list) only the virtual server "vs". The access method and resource are defined in "testResourceGroup", that is referenced from the "testRole". No other operation such as PATCH
(modify) or DELETE is permitted. Also, no other resource such as another virtual is allowed. All the REST calls are done using curl: You may want to consider using other methods such as F5 Python SDK .
1. Create a new user
The following curl command creates the user "foo". The password is "foo", the description is "Foo Bar", and the role is "operator" for all the partitions.
curl -sku admin:<pass> https://<mgmtIP>/mgmt/tm/auth/user -X POST -H "Content-Type: application/json" \ -d '{"name":"foo", "password":"foo", "description":"Foo Bar", "partitionAccess":[ { "name":"all-partitions", "role":"operator"} ] }'
You get the following JSON object:
{ "description": "Foo Bar", "encryptedPassword": "$6$jwL4UUxv$IUrzWGEUsyJaXlOB2oyyTPflHFdvDBXb6f3f/No4KNfQb.V6bpQZBgvxl3KkBDXGtpttej79DDphEGRh8d4iA/", "fullPath": "foo", "generation": 1023, "kind": "tm:auth:user:userstate", "name": "foo", "partitionAccess": [ { "name": "all-partitions", "nameReference": { "link": "https://localhost/mgmt/tm/auth/partition/all-partitions?ver=13.1.1.2" }, "role": "operator" } ], "selfLink": "https://localhost/mgmt/tm/auth/user/satoshi?ver=13.1.1.2" }
The role is important. When the access privileges conflict between the role and the fine grained RBAC, the stricter authorization is chosen. For example, if the RBAC is configured to allow PATCH or POST but the user's role is guest (no alteration allowed), the user won't be able to perform these methods.
You can create a user from tmsh or Configuration Utility if that's your preferred method.
2. (13.1.0 and later) Remove the user from /mgmt/shared/authz/roles/iControl_REST_API_User
/mgmt/shared/authz/roles/iControl_REST_API_User
From v13.1.0, a newly created local user is automatically added to
iControl_REST_API_User
, which grants access to iControl REST without any setup. To avoid assigning multiple permissions, you need to remove the user reference from /mgmt/shared/authz/roles/iControl_REST_API_User
.
First, get the data from
/mgmt/shared/authz/roles/iControl_REST_API_User
and redirect it to a file.
curl -sku admin:<pass> https://<mgmtIP>/mgmt/shared/authz/roles/iControl_REST_API_User \ | python -m json.tool > file
Edit the file. The file contains a line for the user "foo" like this.
"name": "iControl_REST_API_User", "userReferences": [ { "link": "https://localhost/mgmt/shared/authz/users/foo" }, ....
Remove the line including the opening and ending curly brackets plus the comma. Save the file.
Overwrite the current data by putting the file to the endpoint.
curl -sku admin:<pass> https://<mgmtIP>/mgmt/shared/authz/roles/iControl_REST_API_User -X PUT -d@file
3. Create a custom resource-group
A resource-group consists of a set of resources and methods. In this example, the resource-group is named "testResourceGroup", which allows a role to perform
GET
request to the resource /mgmt/tm/ltm/virtual/vs
. "testResourceGroup" is later used in the custom role.
curl -sku admin:<pass> https://<mgmtIP>/mgmt/shared/authz/resource-groups -X POST -H "Content-Type: application/json" \ -d '{"name":"testResourceGroup", "resources":[ {"restMethod":"GET", "resourceMask":"/mgmt/tm/ltm/virtual/vs" } ]}'
You get the following JSON object.
{ "id": "fe7a1ebc-3e61-30aa-8a5d-c7721f7c6ce2", "name": "testResourceGroup", "resources": [ { "resourceMask": "/mgmt/tm/ltm/virtual/vs", "restMethod": "GET" } ], "generation": 1, "lastUpdateMicros": 1521682571723849, "kind": "shared:authz:resource-groups:roleresourcegroupstate", "selfLink": "https://localhost/mgmt/shared/authz/resource-groups/fe7a1ebc-3e61-30aa-8a5d-c7721f7c6ce2" }
Note that a resource-group entry is keyed by "id", not "name". The id is automatically generated.
As you can see, the resources field is a list of multiple objects, each containing the endpoint and the method. To add more permissions to the resource-group, add objects to the list.
4. Create a custom role
Create a role "testRole" with the user "foo" and the resource-groups "testResourceGroup". This makes the user to become a member of the role "testRole", hence allows the users to perform
GET
only to the /mgmt/tm/ltm/virtual/vs
.
curl -sku admin:<pass> https://<mgmtIP>/mgmt/shared/authz/roles -X POST -H "Content-Type: application/json" \ -d '{"name":"testRole", "userReferences":[ {"link":"https://localhost/mgmt/shared/authz/users/foo"} ], "resourceGroupReferences":[{"link":"https://localhost/mgmt/shared/authz/resource-groups/fe7a1ebc-3e61-30aa-8a5d-c7721f7c6ce2"}]}'
Please note that the reference to the user foo in the userReferences field is different from Step #1: The user created was
/mgmt/tm/auth/user/foo
while the reference is /mgmt/shared/authz/users/foo
. The /mgmt/shared/authz/users/foo is automatically created. J
ust use /mgmt/shared/authz/users/
+ user name
.
Again, please observe that the resource-groups reference is not by name but by ID. See the selfLink in the step #3.
You get the following JSON object.
{ "name": "testRole", "userReferences": [ { "link": "https://localhost/mgmt/shared/authz/users/foo" } ], "resourceGroupReferences": [ { "link": "https://localhost/mgmt/shared/authz/resource-groups/fe7a1ebc-3e61-30aa-8a5d-c7721f7c6ce2" } ], "generation": 1, "lastUpdateMicros": 1521682931708662, "kind": "shared:authz:roles:rolesworkerstate", "selfLink": "https://localhost/mgmt/shared/authz/roles/testRole" }
Test
The following REST calls demonstrate that the user "foo" can
GET
the virtual "vs" but nothing else.
curl -D - -sku foo:foo https://192.168.226.155/mgmt/tm/ltm/virtual/vs | grep HTTP HTTP/1.1 200 OK curl -D - -sku foo:foo https://192.168.226.155/mgmt/tm/ltm/virtual | grep HTTP HTTP/1.1 401 F5 Authorization Required curl -D - -sku foo:foo https://192.168.226.155/mgmt/tm/ltm/virtual -X PATCH -d '{"test":"test"}' | grep HTTP HTTP/1.1 401 F5 Authorization Required curl -D - -sku foo:foo https://192.168.226.155/mgmt/tm/sys/version | grep HTTP HTTP/1.1 401 F5 Authorization Required
Cleanup
Removing users that are no longer used is a good admin practice. The cleanup procedure is described below (response JSON blobs are not shown):
1. Delete the resource-group. Use ID.
curl -sku admin:<pass> https://<mgmtIP>/mgmt/shared/authz/resource-groups/fe7a1ebc-3e61-30aa-8a5d-c7721f7c6ce2 -X DELETE
2. Delete the custom role.
curl -sku admin:<pass> https://<mgmtIP>/mgmt/shared/authz/roles/testRole -X DELETE
3. Delete the user.
You can perform this step from tmsh or Configuration Utility.
curl -sku admin:<pass> https://<mgmtIP>/mgmt/tm/auth/user/foo -X DELETE
- dsfraserNimbostratus
I know there is the statement "It does not work for remote authentication mechanisms such as RADIUS or Active Directory." But could this work if I added a local user with the same username and gave it a role? I have tried but if I get a token I can pretty much do anything on the API with my AD user.
- aheilmaierNimbostratus
I also struggle with this sentence.
Will this work if I have in parallel remote authenticaton for i.e. ssh admins ?
Because I get authorization errors and can not find what the reason is.
But with a remote authenticated admin user I do get a response on my get request via curl.
Whre can I check for authentication/authorization ?
Are there any logs ?
I came across the auth issue yesterday after a client called me when getting a 401 for RADIUS authenticated REST API users.
The problem was observed an reproducable in TMOS v12.1.4.1 and v12.1.5.2.
I followed the steps described in K01293626 and the disabling/enabling of remote auth after creating a local account seemed to fix the issue.
After reenabling the remote auth the user was added to the remote role user reference as described in the solution.
Both token based and basic auth based access worked from now.
The solution mentioned above has minor mistakes and little room for optimization as described below (left as comment as well in the solution; got no feedback):
# 6. # - does not require basic auth w/ "-u user:password", because credentials are posted with the payload) # - requires the -H parameter declaration for the content type # - use jq to pipe the output for human readable format curl -sk -H "Content-Type: application/json" -X POST https://<BIGIP address>/mgmt/shared/authn/login -d '{"username": <user>,"password": <password>,"loginProviderName": "tmos"}' | jq # 7. # - does not require the content type declaration, because no data is provided to the service curl -sk -H "X-F5-Auth-Token: <TOKEN>" https://<BIGIP address>/mgmt/tm/ltm/virtual/ | jq
To check the user was assigned to the remote role you might want to use the following:
curl -svk -u 'admin:<admin password>' 'https://<>/mgmt/shared/authz/roles/iControl_REST_API_User/?$select=userReferences' | python -m json.tool
As shown above the python -m json.tool might be use as an alternative to piping via jq depending on availability.
- aheilmaierNimbostratus
I am not sure, but it looks like this fine grained access controll does not work, when tacacs authentication is enabled.
The user I created will be authenticated agains my tacacs remote auth server, and this auth ist failing.
Just checked `/var/log/secure` to see it authc against tacacs.
What TMOS version are you on? Is it TACACS based authentication only or are you using remote roles as well?
For some TMOS versions a TOKEN based REST API access was working only with TACACS (fixed in v15.1.1 according to the release notes).
- aheilmaierNimbostratus
Thank's Stephan, this also clarifies the need for a central authenticated user.
So https://support.f5.com/csp/article/K01293626 also mentions that the user needs to authenticat against radius.
"4. You should be able to log in with the RADIUS credentials."
have not mentinoed I use version 14.1.2.6 and also configured remote roles groups. Hope I do not need a remote-role group also for this user.
- mgateauNimbostratus
Dear all,
Is there a way to automate step 2 : delete the user entry added in iControl_REST_API_User
role using a curl request ?
Addind a user in a role needs to send a PATCH request to /mgmt/shared/authz/roles/<ROLE_NAME>
with json payload '{ "userReferences":[{"link":"https://localhost/mgmt/shared/authz/users/<USER_NAME>"}] }'
But how to delete, with a curl request, an entry in the userReferences array/subcollection (not using your manual method even if the suppression can be done with sed or ...)?
I try to find infos in icontrol user guide pdf but no way (https://cdn.f5.com/websites/devcentral.f5.com/downloads/icontrol-rest-api-user-guide-14-1-0.pdf).
Thanks for help ...
Hi ,
according to an article written by Jason Rahm, you may add items to the list.
But items can be deleted only, if it´s kind of subcollection.
So you may want to replace the whole collection by a new one, as far as I can say.
Kind regards, Stephan
- NicotrelNimbostratus
Good day, Does this method still work in 15.1.2? I have been trying to get it and a similar method (https://support.f5.com/csp/article/K55510624) to work that last couple days. I cannot get either to restrict to only a single VIP or pool.
Thank you, Jason
- nandakumar19Nimbostratus
This is not working for me Version: 14.1.4 Build 0.0.11.