on 18-Nov-2015 03:00
iControl REST. It’s iControl SOAP’s baby, brother, introduced back in TMOS version 11.4 as an early access feature but released fully in version 11.5.
Several articles on basic usage have been written on iControl REST so the intent here isn’t basic use, but rather to demystify some of the finer details of using the API. This article will cover the details on how to retrieve and use an authentication token from the BIG-IP using iControl REST and the python programming language. This token is used in place of basic authentication on API calls, which is a requirement for external authentication. Note that for configuration changes, version 12.0 or higher is required as earlier versions will trigger an un-authorized error.
The details of the token provider are here in the wiki. We’ll focus on a provider not listed there: tmos. This provider instructs the API interface to use the provider that is configured in tmos. For this article, I’ve configured a tacacs server and the BIG-IP with custom remote roles as shown below to show BIG-IP version 12’s iControl REST support for remote authentication and authorization. Details for how this configuration works can be found in the tacacs+ article I wrote a while back.
auth remote-role { role-info { adm { attribute F5-LTM-User-Info-1=adm console %F5-LTM-User-Console line-order 1 role %F5-LTM-User-Role user-partition %F5-LTM-User-Partition } mgr { attribute F5-LTM-User-Info-1=mgr console %F5-LTM-User-Console line-order 2 role %F5-LTM-User-Role user-partition %F5-LTM-User-Partition } } } auth remote-user { } auth source { type tacacs } auth tacacs system-auth { debug enabled protocol ip secret $M$Zq$T2SNeIqxi29CAfShLLqw8Q== servers { 172.16.44.20 } service ppp }
id = tac_plus { debug = PACKET AUTHEN AUTHOR access log = /var/log/access.log accounting log = /var/log/acct.log host = world { address = ::/0 prompt = "\nAuthorized Access Only!\nTACACS+ Login\n" key = devcentral } group = adm { service = ppp { protocol = ip { set F5-LTM-User-Info-1 = adm set F5-LTM-User-Console = 1 set F5-LTM-User-Role = 0 set F5-LTM-User-Partition = all } } } group = mgr { service = ppp { protocol = ip { set F5-LTM-User-Info-1 = mgr set F5-LTM-User-Console = 1 set F5-LTM-User-Role = 100 set F5-LTM-User-Partition = all } } } user = user_admin { password = clear letmein00 member = adm } user = user_mgr { password = clear letmein00 member = mgr } }
Before we look at code, however, let’s take a look at the json payload requirements, followed by response data from a query using Chrome’s Advanced REST Client plugin. First, since we are sending json payload, we need to add the Content-Type: application/json header to the query. The payload we are sending with the post looks like this:
{ "username": "remote_auth_user", "password": "remote_auth_password", "loginProviderName": "tmos" }
You submit the same remote authentication credentials in the initial basic authentication as well, no need to have access to the default admin account credentials. A successful query for a token returns data like this:
{ username: "user_admin" loginReference: { link: "https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/login" }- token: { uuid: "4d1bd79f-dca7-406b-8627-3ad262628f31" name: "5C0F982A0BF37CBE5DE2CB8313102A494A4759E5704371B77D7E35ADBE4AAC33184EB3C5117D94FAFA054B7DB7F02539F6550F8D4FA25C4BFF1145287E93F70D" token: "5C0F982A0BF37CBE5DE2CB8313102A494A4759E5704371B77D7E35ADBE4AAC33184EB3C5117D94FAFA054B7DB7F02539F6550F8D4FA25C4BFF1145287E93F70D" userName: "user_admin" user: { link: "https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/users/34ba3932-bfa3-4738-9d55-c81a1c783619" }- groupReferences: [1] 0: { link: "https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/user-groups/21232f29-7a57-35a7-8389-4a0e4a801fc3" }- - timeout: 1200 startTime: "2015-11-17T19:38:50.415-0800" address: "172.16.44.1" partition: "[All]" generation: 1 lastUpdateMicros: 1447817930414518 expirationMicros: 1447819130415000 kind: "shared:authz:tokens:authtokenitemstate" selfLink: "https://localhost/mgmt/shared/authz/tokens/4d1bd79f-dca7-406b-8627-3ad262628f31" }- generation: 0 lastUpdateMicros: 0 }
Among many other fields, you can see the token field with a very long hexadecimal token. That’s what we need to authenticate future API calls.
In order to request the token, you first have to supply basic auth credentials like normal. This is currently required to access the /mgmt/shared/authn/login API location. The basic workflow is as follows (with line numbers from the code below in parentheses):
And here’s the code (in python) to make that happen:
def create_pool(bigip, url, pool): payload = {} payload['name'] = pool pool_config = bigip.post(url, json.dumps(payload)).json() return pool_config def get_token(bigip, url, creds): payload = {} payload['username'] = creds[0] payload['password'] = creds[1] payload['loginProviderName'] = 'tmos' token = bigip.post(url, json.dumps(payload)).json()['token']['token'] return token if __name__ == "__main__": import os, requests, json, argparse, getpass requests.packages.urllib3.disable_warnings() parser = argparse.ArgumentParser(description='Remote Authentication Test - Create Pool') parser.add_argument("host", help='BIG-IP IP or Hostname', ) parser.add_argument("username", help='BIG-IP Username') parser.add_argument("poolname", help='Key/Cert file names (include the path.)') args = vars(parser.parse_args()) hostname = args['host'] username = args['username'] poolname = args['poolname'] print "%s, enter your password: " % args['username'], password = getpass.getpass() url_base = 'https://%s/mgmt' % hostname url_auth = '%s/shared/authn/login' % url_base url_pool = '%s/tm/ltm/pool' % url_base b = requests.session() b.headers.update({'Content-Type':'application/json'}) b.auth = (username, password) b.verify = False token = get_token(b, url_auth, (username, password)) print '\nToken: %s\n' % token b.auth = None b.headers.update({'X-F5-Auth-Token': token}) response = create_pool(b, url_pool, poolname) print '\nNew Pool: %s\n' % response
Running this script from the command line, we get the following response:
FLD-ML-RAHM:scripts rahm$ python remoteauth.py 172.16.44.15 user_admin myNewestPool1 Password: user_admin, enter your password: Token: 2C61FE257C7A8B6E49C74864240E8C3D3592FDE9DA3007618CE11915F1183BF9FBAF00D09F61DE15FCE9CAB2DC2ACC165CBA3721362014807A9BF4DEA90BB09F New Pool: {u'generation': 453, u'minActiveMembers': 0, u'ipTosToServer': u'pass-through', u'loadBalancingMode': u'round-robin', u'allowNat': u'yes', u'queueDepthLimit': 0, u'membersReference': {u'isSubcollection': True, u'link': u'https://localhost/mgmt/tm/ltm/pool/~Common~myNewestPool1/members?ver=12.0.0'}, u'minUpMembers': 0, u'slowRampTime': 10, u'minUpMembersAction': u'failover', u'minUpMembersChecking': u'disabled', u'queueTimeLimit': 0, u'linkQosToServer': u'pass-through', u'queueOnConnectionLimit': u'disabled', u'fullPath': u'myNewestPool1', u'kind': u'tm:ltm:pool:poolstate', u'name': u'myNewestPool1', u'allowSnat': u'yes', u'ipTosToClient': u'pass-through', u'reselectTries': 0, u'selfLink': u'https://localhost/mgmt/tm/ltm/pool/myNewestPool1?ver=12.0.0', u'serviceDownAction': u'none', u'ignorePersistedWeight': u'disabled', u'linkQosToClient': u'pass-through'}
You can test this out in the Chrome Advanced Rest Client plugin, or from the command line with curl or any other language supporting REST clients as well, I just use python for the examples well, because I like it. I hope you all are digging into iControl REST! What questions do you have? What else would you like clarity on? Drop a comment below.
Hello 🙂
I was trying to get a script to work with F5 APIs, but seems I need to authenticate with tacacs first... I was trying to change the script to Powerhsell and obtain the token, but I'm always getting '(401) Not authorized'. What I'm using: $body= @" { "username": "f5_user", "password": "f5_user_password", "loginProviderName": "tmos" } "@ $token=Invoke-RestMethod -Uri https://f5_ip_addr/mgmt/shared/authn/login -ContentType 'application/json' -Body $body -Method Post
I'm mostly sure I'm missing something, but been reading the F5 site and other sites and can't get to it... can anyone provide some help? The final objective is to be able to make calls via the F5 APIs, to get stuff like node current connections, etc.
Really appreciate any input. Thank you!
Hello Jason 🙂
I still get a 401 access denied error, think it's something on F5 side. Need to request to the managing team to verify the appropriate privileges. Anyway, I'm getting around this error using the iControl Powershell module, so should be able to reach the same result and no errors authenticating with the F5.
Thank you for your help!
Jason R,
I've been trying to get this working with 11.5.1 Build 8.0.175 Hotfix HF8. The Authentication User Directory is 'Remote - Active Directory'. Regardless of the loginProviderName I send, the result is 404 Not Found: And, I cannot locate a loginReference uuid or link anywhere.
Is there some active directory specific documentation to which I can refer, or is token retrieval simply not viable in 11.5.1 Build 8.0.175 Hotfix HF8?
Jason V.
Hi,
I have two different environments where I'm testing this. I'm getting the RESTAPI to work fine with my TMOS 12.1 environment but in 11.6.1 I'm getting 401 error.
12.1
curl -sk --header "Content-Type:application/json" --request POST https://localhost/mgmt/shared/authn/login --data '{"username":"aduser", "password":"adpassword", "loginProviderName":"tmos"}'
{"username":"aduser","loginReference":{"link":"https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/login"},"loginProviderName":"tmos","token":{"token":"4F7P62K5BL2UIN4ZSW3DMWTAKC","name":"4F7P62K5BL2UIN4ZSW3DMWTAKC","userName":"anfo","authProviderName":"tmos","user":{"link":"https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/users/4f446f2a-9922-469a-ac69-656d770e8408"},"groupReferences":[{"link":"https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/user-groups/21232f29-7a57-35a7-8389-4a0e4a801fc3"}],"timeout":1200,"startTime":"2016-09-14T14:25:47.986+0200","address":"127.0.0.1","partition":"[All]","generation":1,"lastUpdateMicros":1473855947986173,"expirationMicros":1473857147986000,"kind":"shared:authz:tokens:authtokenitemstate","selfLink":"https://localhost/mgmt/shared/authz/tokens/4F7P62K5BL2UIN4ZSW3DMWTAKC"},"generation":0,"lastUpdateMicros":0}[
curl -sk --header "Content-Type:application/json" --header "X-F5-Auth-Token: 4F7P62K5BL2UIN4ZSW3DMWTAKC" --request GET https://localhost/mgmt/shared/echo
{"stage":"STARTED","stageEnumValues":["CREATED","STARTED","SHUTDOWN"],"generation":0,"lastUpdateMicros":0,"kind":"shared:echo:echoworkerstate","selfLink":"https://localhost/mgmt/shared/echo"}
11.6.1
curl -sk --header "Content-Type:application/json" --request POST https://localhost/mgmt/shared/authn/login --data '{"username":"aduser", "password":"adpassword", "loginProviderName":"tmos"}'
{"username":"aduser","loginReference":{"link":"https://localhost/mgmt/shared/authn/providers/local/login"},"token":{"uuid":"af2323bb-295f-4c21-a2ad-bc874d96b6a3","name":"39EBC4D277ECE08D5AFE4EC57B05674F194291BC6959079F188816267CA22CD9E1E8AB3CD44DE8C846A3A9A0AD9BD93F4C65B9C0BCFA969B8AF465CE2BD5A0BE","token":"39EBC4D277ECE08D5AFE4EC57B05674F194291BC6959079F188816267CA22CD9E1E8AB3CD44DE8C846A3A9A0AD9BD93F4C65B9C0BCFA969B8AF465CE2BD5A0BE","userName":"aduser","user":{"link":"https://localhost/mgmt/shared/authz/users/aduser"},"groupReferences":[],"timeout":1200,"startTime":"2016-09-14T05:03:15.763-0700","address":"127.0.0.1","partition":"[All]","generation":1,"lastUpdateMicros":1473854595759258,"expirationMicros":1473855795763000,"kind":"shared:authz:tokens:authtokenitemstate","selfLink":"https://localhost/mgmt/shared/authz/tokens/af2323bb-295f-4c21-a2ad-bc874d96b6a3"},"generation":0,"lastUpdateMicros":0}
curl -sk --header "Content-Type:application/json" --header "X-F5-Auth-Token: 39EBC4D277ECE08D5AFE4EC57B05674F194291BC6959079F188816267CA22CD9E1E8AB3CD44DE8C846A3A0AD9BD93F4C65B9C0BCFA969B8AF465CE2BD5A0BE" --request GET https://localhost/mgmt/tm/ltm/pool?$select=name
{"code":401,"message":"Authorization failed: user=https://localhost/mgmt/shared/authz/users/aduser resource=/mgmt/tm/ltm/pool verb=GET uri:http://localhost:8100/mgmt/tm/ltm/pool?=name referrer:127.0.0.1 sender:127.0.0.1","referer":"127.0.0.1","restOperationId":12574003,"errorStack":["java.lang.SecurityException: Authorization failed: user=https://localhost/mgmt/shared/authz/users/aduser resource=/mgmt/tm/ltm/pool verb=GET uri:http://localhost:8100/mgmt/tm/ltm/pool?=name referrer:127.0.0.1 sender:127.0.0.1","at com.f5.rest.workers.ForwarderWorker.failPermissionValidation(ForwarderWorker.java:565)","at com.f5.rest.workers.ForwarderWorker.evaluateUserPermission(ForwarderWorker.java:633)","at com.f5.rest.workers.ForwarderWorker.evaluatePermission(ForwarderWorker.java:537)","at com.f5.rest.workers.ForwarderPassThroughWorker.onForward(ForwarderPassThroughWorker.java:202)","at com.f5.rest.workers.ForwarderPassThroughWorker.onGet(ForwarderPassThroughWorker.java:370)","at com.f5.rest.common.RestWorker.callDerivedRestMethod(RestWorker.java:1009)","at com.f5.rest.common.RestWorker.callRestMethodHandler(RestWorker.java:976)","at com.f5.rest.common.RestServer.processQueuedRequests(RestServer.java:889)","at com.f5.rest.common.RestServer.access$000(RestServer.java:43)","at com.f5.rest.common.RestServer$1.run(RestServer.java:165)","at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)","at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)","at java.lang.Thread.run(Thread.java:744)\n"]}
One thing i noticed is the difference in the user path response from the different versions.
12.1: https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/login
11.6.1: https://localhost/mgmt/shared/authn/providers/local/login
`
I have tried to create a local user on the 11.6.1 system but I don't think this will help because the RESTAPI users does not work when changing the Auth type from Local to my case "Active Directory". The only local accounts that works then is the admin and root accounts.
Best Regards Andréas
Hi, Jason,
Are you saying that getting an auth token isn't expected to work at all before 12.0, or just with a LoginReference. I'm getting an auth token without issue in 11.6 HF4.
However, I'm not having any luck setting the timeout to a non-standard value, using a variation of Casey Robertson' JSON. Is that JSON valid, and is it documented anywhere?
Cheers, Joel
tokens will work, but tokens with remote authentication like tacacs+ or ldap are not expected to work. I personally haven't dealt with non-standard timeouts and if not documented in the user guides, I'd question the reliability of doing so.
Finally I was able to run token based auth with big-ip 11.6.1 and ldap auth provider. I found the login provider reference while I was playing with restcurl cm | grep providers | tail -1
and then simply changed the tailing user-group to login:
example:
"loginReference":{"link": "https://localhost/mgmt/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/login"}
Hope this works for others aswell.
Im new to REST API scripting so Im probably making a simple mistake here, but Im using Postman to generate a POST request to get a token. Im hitting .
I have authorization set to basic and in Body Im sending:
{
"username":"admin",
"password":"password",
"loginProvidername":"tmos"
}
with the actual password for the admin account.
I keep getting:
{
"code": 401,
"message": "Cannot use 'local' auth provider name when system auth source type is not 'local'",
"originalRequestBody": "{\"username\":\"admin\",\"generation\":0,\"lastUpdateMicros\":0}",
"referer": "10.238.90.21",
"restOperationId": 37917423,
"kind": ":resterrorresponse"
}
I've Googled myself cross-eyed and haven't come across anything helpful. We use RADIUS authentication for access to our F5s. Based on this error message I think that has something to do with this. It seems that it doesn't like me using a local account when the box is configured for RADIUS, but I can't figure out how to change the post to use RADIUS. I've tried using a known good RADIUS account and that fails with the same message. The local account works with basic authentication when doing a GET to something like /mgmt/tm/ltm, but not when I do a POST to the /mgmt/shared/authn/login.
I am testing this against version 13.1.0.8.
Please try "loginProviderName":"tmos" instead (note the capital "N" in the JSON property)
Thanks Dan, that was the issue! I can't believe it, after all the time I spent trying different things and scouring the internet for an answer!
You can probably set the timeout for the token you have received and verify it or generate a new one (as by now you know when to check).
Use this API
<PATCH>https://{{bigip_a_mgmt}}/mgmt/shared/authz/tokens/{{bigip_a_auth_token}}
{
"timeout":"36000"
}
in headers add "X-F5-Auth-Token" = {{bigip_a_auth_token}}