ONTAP Rest API Discussions

How do we authenticate using cert instead of password for REST APIs access

Juluri
10,897 Views

Hi,

 

I am trying to understand if we can use cert as authentication process instead of password for REST APIs access

I checked the API document and all I can see is password based authentication only (below content is from API documentation)

 

#####################################

HTTP authentication Process for REST API:-

At an HTTP level, basic authentication is used for the API transactions. An HTTP header with the user name and password in a base64 string is added to each request

curl -X GET -u username:password -k 'https://<ip_address>/api/cluster? fields=version'

#####################################

 

Any idea if we can use  purely use certs for authentication, basically I am trying to implement password less authentication. Kindly let me know, Thanks.

 

Thanks,

-Srini

1 ACCEPTED SOLUTION

RobertBlackhart
10,715 Views

Not having an intermediate CA is not a problem; it's not required.

 

For your last post, that would be expected. The server cert is what is sent for the client to validate the server identity. This is the same function as the certificate that you would get from going to https://google.com, for example. You local machine checks the root CA provided in that certificate and makes sure it trusts it. Passing -k to curl makes curl skip this trust check.

 

Right now we're trying to deal with the certificate validation going in the other way. That is, the client is sending the server a certificate and the server must declare if it trusts the root that signed it as well as the contents of it, which is where the failure is happening (the 401).

 

I'm not too sure what the remaining issue might be. I may have to tap out here and suggest that you open a ticket with support who may have more experience in getting this to work. If you do find the solution though, I wouldn't mind hearing what it was.

View solution in original post

8 REPLIES 8

RobertBlackhart
10,890 Views

Yes, you can use certificate/key authentication with the rest API. Here's a basic workflow for it:

================================================================================
= As the administrative account, create a new root_ca certificate which will be
= used to sign all certificate requests for the user accounts you'd like to be
= able to authenticate
================================================================================

cycrh6rtp20:~/$ curl -iku admin -X POST -d '{"type": "root_ca", "common_name": "MyCompany", "expiry_time": "3652days"}' https://<cluster_mgmt>/api/security/certificates
Enter host password for user 'admin':
HTTP/1.1 201 Created
Date: Fri, 02 Oct 2020 10:07:54 GMT
Server: libzapid-httpd
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
Location: /api/security/certificates/23c38b55-0497-11eb-b855-005056bb97cc
Content-Length: 3
Content-Type: application/hal+json

{
}cycrh6rtp20:~/$

================================================================================
= Create a certificate signing request for the user that you want. The common_name
= in the request must match the username in ONTAP
================================================================================

cycrh6rtp20:~/$ openssl genrsa -out cert_user.key 2048
Generating RSA private key, 2048 bit long modulus
..................+++
................................................................................................+++
e is 65537 (0x10001)
cycrh6rtp20:~/$ openssl req -sha256 -new -nodes -key cert_user.key -subj /C=US/ST=PA/L=Pittsburgh/O=MyCompany/OU=BestPart/CN=ricky_bobby -out cert_user.csr
cycrh6rtp20:~/$

================================================================================
= Have ONTAP sign the certificate request with the root CA we created earlier
= and save the response to a file
================================================================================

cycrh6rtp20:~/$ curl -iku admin -X POST -d '{"signing_request": "-----BEGIN CERTIFICATE REQUEST-----
MIICsTCCAZkCAQAwbDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlBBMRMwEQYDVQQH
DApQaXR0c2J1cmdoMRIwEAYDVQQKDAlNeUNvbXBhbnkxETAPBgNVBAsMCEJlc3RQ
YXJ0MRQwEgYDVQQDDAtyaWNreV9ib2JieTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAL49TSzQTP3CaBKz461n1UGdiculboS+e76sBbjNVl58mO0qsREi
V8WNSNblZbJGbkz4rotUO4YQIizs0w7iMyQaEgZbysBYG4OXYW6duZg/kCkbpchz
vI/q+Uqbg5WAbS2DyPx0GhfUpxnld2NVoH1yBFG8auJZ7Z2UVkpeFouyfOy6JQAz
oF8fnHCENN7Wh7HlYF0I+mf9KW2HN5790TbgLx6Yaz4uiQ+eK/vWgGFJjTi5Am/x
FbNLnafTL5o6mk9WhqJamYLhxm2FY04Z0RvHtPC5i/30qj8MrfvmI144RvIuBPUz
vyvRv9JzRxfo6C6PCj2XDdWMWVtAJikOXa8CAwEAAaAAMA0GCSqGSIb3DQEBCwUA
A4IBAQB2oMYRhiemhZq5RdtekDKDh6C7QiRclmJUZQuOB9Dac9pwJO/oSC0+668I
TTCdLY+L7YQ96V2X34Pau0HzIiPlxyJm6ZzNf9pXBIeJWwzdG5/LXTQqg/LlT1Rl
utBwemSuBSQdij1EEEpuY+vHkftDTQMkgkOWB5EWlTzzVQzswIFbES/IOyxBY7s9
WD3d/GAD/UHBX5uKYvvm3WKJrf5UifPUJBqm+BjK1qcseCyNFpurRxwUKyjerI0W
oRdRtdjYM7wYZyvT9YlKBUcvNMmkIw0LIFwVhk2hBXM2+BJtGfdeHyFfOujjdRkh
ncnwe1Sy2w8Mi/I6aAh6sM6QtWv5
-----END CERTIFICATE REQUEST-----"}' https://<cluster_mgmt>/api/security/certificates/23c38b55-0497-11eb-b855-005056bb97cc/sign
Enter host password for user 'admin':
HTTP/1.1 100 Continue

HTTP/1.1 200 OK
Date: Fri, 02 Oct 2020 10:15:58 GMT
Server: libzapid-httpd
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
Content-Length: 1274
Content-Type: application/hal+json

{
  "public_certificate": "-----BEGIN CERTIFICATE-----\nMIIDXDCCAkSgAwIBAgIIFjolasqTdLgwDQYJKoZIhvcNAQELBQAwITESMBAGA1UE\nAxMJTXlDb21wYW55MQswCQYDVQQGEwJVUzAeFw0yMDEwMDIxMDE1NThaFw0yMTEw\nMDIxMDE1NThaMGwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJQQTETMBEGA1UEBwwK\nUGl0dHNidXJnaDESMBAGA1UECgwJTXlDb21wYW55MREwDwYDVQQLDAhCZXN0UGFy\ndDEUMBIGA1UEAwwLcmlja3lfYm9iYnkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQC+PU0s0Ez9wmgSs+OtZ9VBnYnLpW6Evnu+rAW4zVZefJjtKrERIlfF\njUjW5WWyRm5M+K6LVDuGECIs7NMO4jMkGhIGW8rAWBuDl2FunbmYP5ApG6XIc7yP\n6vlKm4OVgG0tg8j8dBoX1KcZ5XdjVaB9cgRRvGriWe2dlFZKXhaLsnzsuiUAM6Bf\nH5xwhDTe1oex5WBdCPpn/Slthzee/dE24C8emGs+LokPniv71oBhSY04uQJv8RWz\nS52n0y+aOppPVoaiWpmC4cZthWNOGdEbx7TwuYv99Ko/DK375iNeOEbyLgT1M78r\n0b/Sc0cX6Ogujwo9lw3VjFlbQCYpDl2vAgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYD\nVR0OBBYEFBiErwnY2ZaAEuzX/ggjHJ9JMN+bMB8GA1UdIwQYMBaAFAldpMFmjRvm\nPlhx0COQtmtMB/K2MA0GCSqGSIb3DQEBCwUAA4IBAQDBJ3iYfOf5zHj1duych9Z8\nN2S4CJJqUrzYGuP7h+0nQK1wM3QnzUZGuv2h60kZ5lNItS0RbpWxViZNPuFfMvsC\n0hP6M1eLIXl39N1U6c/T4KOUZBOwW50kRLp5jJycMTNLrbE+g+43JbP94Y5f/JN4\n/HdwXnodCFslPSHj+x/5IFLTL6aCBD0b+6DW5DYHd6jORxN0xYlEzI5SxKdRlbAp\nBpJYEUZg1DK84Ojb9fuLOUeFvFA4oSpoH/nbqtGlGmODrzzZTZs8IU9/C4kXC/qC\n37fjbviTn/aQbMxIpW3jfAWsVcMohvfL+lUnZ8hmtZDXLuxvFu3C/MHLIuUuTX2x\n-----END CERTIFICATE-----\n"
}cycrh6rtp20:~/$ echo -e "-----BEGIN CERTIFICATE-----\nMIIDXDCCAkSgAwIBAgIIFjolasqTdLgwDQYJKoZIhvcNAQELBQAwITESMBAGA1UE\nAxMJTXlDb21wYW55MQswCQYDVQQGEwJVUzAeFw0yMDEwMDIxMDE1NThaFw0yMTEw\nMDIxMDE1NThaMGwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJQQTETMBEGA1UEBwwK\nUGl0dHNidXJnaDESMBAGAUECgwJTXlDb21wYW55MREwDwYDVQQLDAhCZXN0UGFy\ndDEUMBIGA1UEAwwLcmlja3lfYm9iYnkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQC+PU0s0Ez9wmgSs+OtZ9VBnYnLpW6Evnu+rAW4zVZefJjtKrERIlfF\njUjW5WWyRm5M+K6LVDuGECIs7NMO4jMkGhIGW8rAWBuDl2FunbmYP5ApG6XIc7yP\n6vlKm4OVgG0tg8j8dBoX1KcZ5XdjVaB9cgRRvGriWe2dlFZKXhaLsnzsuiUAM6Bf\nH5xwhDTe1oex5WBdCPpn/Slthzee/dE24C8emGs+LokPniv71oBhSY04uQJv8RWz\nS52n0y+aOppPVoaiWpmC4cZthWNOGdEbx7TwuYv99Ko/DK375iNeOEbyLgT1M78r\n0b/Sc0cX6Ogujwo9lw3VjFlbQCYpDl2vAgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYD\nVR0OBBYEFBiErwnY2ZaAEuzX/ggjHJ9JMN+bMB8GA1UdIwQYMBaAFAldpMFmjRvm\nPlhx0COQtmtMB/K2MA0GCSqGSIb3DQEBCwUAA4IBAQDBJ3iYfOf5zHj1duych9Z8\nN2S4CJJqUrzYGuP7h+0nQK1wM3QnzUZGuv2h60kZ5lNItS0RbpWxViZNPuFfMvsC\n0hP6M1eLIXl39N1U6c/T4KOUZBOwW50kRLp5jJycMTNLrbE+g+43JbP94Y5f/JN4\n/HdwXnodCFslPSHj+x/5IFLTL6aCBD0b+6DW5DYHd6jORxN0xYlEzI5SxKdRlbAp\nBpJYEUZg1DK84Ojb9fuLOUeFvFA4oSpoH/nbqtGlGmODrzzZTZs8IU9/C4kXC/qC\n37fjbviTn/aQbMxIpW3jfAWsVcMohvfL+lUnZ8hmtZDXLuxvFu3C/MHLIuUuTX2x\n-----END CERTIFICATE-----\n" > cert_user.crt
cycrh6rtp20:~/$

================================================================================
= Create a user account in ONTAP with a username matching our certificate's
= common name
================================================================================

cycrh6rtp20:~/$ curl -iku admin -X POST -d '{"name": "ricky_bobby", "applications": [{"application": "http", "authentication_methods": ["cert"]}]}' https://<cluster_mgmt>/api/security/accounts
Enter host password for user 'admin':
HTTP/1.1 201 Created
Date: Fri, 02 Oct 2020 10:19:34 GMT
Server: libzapid-httpd
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
Location: /api/security/accounts/2327973e-ff18-11ea-9dc7-005056bb97cc/ricky_bobby
Content-Length: 3
Content-Type: application/hal+json

{
}cycrh6rtp20:~/$

================================================================================
= Now we can authenticate to the API as our user by passing our certificate and key
================================================================================

cycrh6rtp20:~/$ curl -ik --cert cert_user.crt --key cert_user.key https://<cluster_mgmt>/api/cluster?fields=version
HTTP/1.1 200 OK
Date: Fri, 02 Oct 2020 10:20:37 GMT
Server: libzapid-httpd
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
Content-Length: 221
Content-Type: application/hal+json

{
  "version": {
    "full": "NetApp Release Cloudwalker__9.9.0: Mon Sep 28 12:10:37 UTC 2020",
    "generation": 9,
    "major": 9,
    "minor": 0
  },
  "_links": {
    "self": {
      "href": "/api/cluster"
    }
  }
}cycrh6rtp20:~/$

================================================================================
= If you want to limit the scope of the user and what they can do, you can change
= the user's role from admin to something custom that has only the permissions
= you want
================================================================================

cycrh6rtp20:~/$ curl -iku admin -X POST -d '{"name": "volume_reader", "privileges": [{"access": "readonly", "path": "/api/storage/volumes"}]}' https://<cluster_mgmt>/api/security/roles
Enter host password for user 'admin':
HTTP/1.1 201 Created
Date: Fri, 02 Oct 2020 10:25:52 GMT
Server: libzapid-httpd
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
Location: /api/security/roles/2327973e-ff18-11ea-9dc7-005056bb97cc/volume_reader
Content-Length: 3
Content-Type: application/hal+json

{
}cycrh6rtp20:~/$
cycrh6rtp20:~/$ curl -iku admin -X PATCH -d '{"role": {"name": "volume_reader"}}' https://<cluster_mgmt>/api/security/accounts/2327973e-ff18-11ea-9dc7-005056bb97cc/ricky_bobby
Enter host password for user 'admin':
HTTP/1.1 200 OK
Date: Fri, 02 Oct 2020 10:26:50 GMT
Server: libzapid-httpd
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
Content-Length: 3
Content-Type: application/hal+json

{
}cycrh6rtp20:~/$

================================================================================
= Now our previous cluster API call will fail, but we can still get a list of
= volumes from the API
================================================================================

cycrh6rtp20:~/$ curl -ik --cert cert_user.crt --key cert_user.key https://<cluster_mgmt>/api/cluster?fields=version
HTTP/1.1 403 Forbidden
Date: Fri, 02 Oct 2020 10:27:30 GMT
Server: libzapid-httpd
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
Content-Length: 86
Content-Type: application/hal+json

{
  "error": {
    "message": "not authorized for that command",
    "code": "6"
  }
}cycrh6rtp20:~/$ curl -ik --cert cert_user.crt --key cert_user.key https://<cluster_mgmt>/api/storage/volumes?return_records=false
HTTP/1.1 200 OK
Date: Fri, 02 Oct 2020 10:27:58 GMT
Server: libzapid-httpd
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
Content-Length: 119
Content-Type: application/hal+json

{
  "num_records": 5,
  "_links": {
    "self": {
      "href": "/api/storage/volumes?return_records=false"
    }
  }
}cycrh6rtp20:~/$

Juluri
10,858 Views

Thank you very much Robert for swift response with detailed info.

I tried executing the posted procedure , unfortunately its giving error, I see authorization error, please see below.

 

HTTP/1.1 401 Unauthorized
Date: Fri, 02 Oct 2020 14:10:58 GMT
Server: Apache
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
WWW-Authenticate: Basic realm="ONTAP"
Content-Length: 381
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Unauthorized</title>
</head><body>
<h1>Unauthorized</h1>
<p>This server could not verify that you
are authorized to access the document
requested. Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
</body></html>

 

Not sure what's the issue, I have also tried executing all cert commands directly on storage but no luck, same error with this process as well

 

Here is what I have followed manually

 

1)Created root CA
2)Generated SSL certificate
3)Signed the generated SSL certificate by root CA cert
4)Installed CA signed certificate with type "server"
5)while accessing API, provided CA signed Cert and Private key details

 

Any idea what could be the issue here, thanks - Srini

 

 

RobertBlackhart
10,856 Views

I don't think you need/want to install the certificate that you had signed back on the cluster. That is only needed on the client side. The important parts of that are that it is signed by a CA that is installed on the cluster and that the common name in that certificate matches the username of the account that you want to authenticate as.

 

You didn't mention any details about the user you are trying to authenticate as. But make sure that account has the http application and cert authentication method enabled. That is also required and not mentioned in your steps below.

Juluri
10,850 Views

Hi Robert,

 

Thank you for clarifying on certs stuff.

Yeah, the account I used is matching with the common name used for the cert, please see details below

 

Second
User/Group Authentication Acct Authentication
Name Application Method Role Name Locked Method
-------------- ----------- ------------- ---------------- ------ --------------
apiread http cert admin - none

 

This is the command I used to create this account

 

curl -iku admin -X POST -d '{"name": "apiread", "applications": [{"application": "http", "authentication_methods": ["cert"]}]}' https://<cdotname>/api/security/accounts

 

And please see below command which I executed for cert

 

openssl req -sha256 -new -nodes -key cert_user.key -subj /C=IE/ST=""/L=Dublin/O=<mycompany>/OU=BestPart/CN=apiread -out cert_user.csr

 

Kindly advise.

 

 

Thanks,

-Srini

 

 

 

RobertBlackhart
10,848 Views

Was the root CA that you created in step one installed on the cluster (type root_ca)? If not, I think that would cause the issue as well since the cluster wouldn't have a CA available by which to verify the certificate that curl is providing.

Juluri
10,814 Views

Hi Robert,

 

Thank you for checking and responding on this.

Yeah, I verified it and see that root CA exists fine, please see below

 

###Replaced actual values with dummy value for security reasons###
Vserver Serial Number Certificate Name Type
---------- --------------- -------------------------------------- ------------
<adminSVMname>
<Serialno>
<CertName>
root-ca
Certificate Authority: <CA>
Expiration Date: Wed Oct 02 13:55:51 2030

 

I am wondering with this process, we were able to create root-ca and signed cert however intermediate cert is not there here.

Any idea if that is causing the issue because what is understand is, always cert verification starts with low level signed- cert>intermediate cert>root cert

 

Also tried by providing root CA cert to the command using switch "--cacert" (this has root ca cert value) as shown below however no luck( its giving same unauthorized error)

 

curl -ik --cacert cert_user_ca.crt --cert cert_user.crt --key cert_user.key https://<adminsvmname>/api/cluster?fields=version

 

***Error Details***

 

HTTP/1.1 401 Unauthorized
Date: Sat, 03 Oct 2020 07:13:34 GMT
Server: Apache
X-Content-Type-Options: nosniff
Cache-Control: no-cache,no-store,must-revalidate
WWW-Authenticate: Basic realm="ONTAP"
Content-Length: 381
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Unauthorized</title>
</head><body>
<h1>Unauthorized</h1>
<p>This server could not verify that you
are authorized to access the document
requested. Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
</body></html>

 

*******************************************

 

 

Juluri
10,813 Views

Hi Robert,

 

I think I found the problem,  I ran the command in verbose mode and see that  it is checking "server" cert instead of "root-ca" cert, I have two certs with same common name (server and root-ca),  Kindly review this and advise.Thanks

 

Please see below verbose o/p

 

* About to connect() to <adminsvmname> port 443 (#0)
* Trying xxx.xx.xxx.xx...
* Connected to <adminsvmname> (xxx.xx.xxx.xx) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate: --------------------------------------> This is Server cert, looks like it is validating against this instead of root-CA-cert
* subject: C=US,CN=<adminsvmname>
* start date: Oct 03 08:04:42 2020 GMT
* expire date: Oct 03 08:04:42 2021 GMT
* common name: <adminsvmname>
* issuer: C=US,CN=<adminsvmname>
> GET /api/cluster?fields=version HTTP/1.1
> User-Agent: curl/7.29.0
> Host: <adminsvmname>
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
HTTP/1.1 401 Unauthorized
< Date: Sat, 03 Oct 2020 08:07:11 GMT
Date: Sat, 03 Oct 2020 08:07:11 GMT
< Server: Apache
Server: Apache
< X-Content-Type-Options: nosniff
X-Content-Type-Options: nosniff
< Cache-Control: no-cache,no-store,must-revalidate
Cache-Control: no-cache,no-store,must-revalidate
< WWW-Authenticate: Basic realm="ONTAP"
WWW-Authenticate: Basic realm="ONTAP"
< Content-Length: 381
Content-Length: 381
< Content-Type: text/html; charset=iso-8859-1
Content-Type: text/html; charset=iso-8859-1

<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Unauthorized</title>
</head><body>
<h1>Unauthorized</h1>
<p>This server could not verify that you
are authorized to access the document
requested. Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
</body></html>
* Connection #0 to host <adminsvmname> left intact

RobertBlackhart
10,716 Views

Not having an intermediate CA is not a problem; it's not required.

 

For your last post, that would be expected. The server cert is what is sent for the client to validate the server identity. This is the same function as the certificate that you would get from going to https://google.com, for example. You local machine checks the root CA provided in that certificate and makes sure it trusts it. Passing -k to curl makes curl skip this trust check.

 

Right now we're trying to deal with the certificate validation going in the other way. That is, the client is sending the server a certificate and the server must declare if it trusts the root that signed it as well as the contents of it, which is where the failure is happening (the 401).

 

I'm not too sure what the remaining issue might be. I may have to tap out here and suggest that you open a ticket with support who may have more experience in getting this to work. If you do find the solution though, I wouldn't mind hearing what it was.

Public