Is X509 authentication (certificate/keys) possible for Confd REST northbound interface in 2019?
Is there any plan of adding other authentication mechanisms for Confd REST/NETCONF any time soon?
I’m asking this question to get any updates for an answer to a similar question asked in 2015
UPDATE: A demo project can be found here: https://github.com/ConfD-Developer/ConfD-Demos/tree/master/tls-restconf
Glad you asked. See ConfD UG 7.2 or later under “Storing TLS data in database”.
Here is a simple RESTCONF x509 example for ConfD 7.2:
$ pwd
/Users/tailf/confd-7.2.1/examples.confd/restconf/basic
$ diff -u confd.conf.old confd.conf
--- confd.conf.old 2019-10-19 14:37:52.000000000 +0200
+++ confd.conf 2019-11-20 06:23:51.000000000 +0100
@@ -230,10 +230,14 @@
<docroot>.</docroot>
<transport>
<tcp>
+ <enabled>false</enabled>
+ </tcp>
+ <ssl>
<enabled>true</enabled>
<ip>127.0.0.1</ip>
- <port>8008</port>
- </tcp>
+ <port>8888</port>
+ <readFromDb>true</readFromDb>
+ <protocols>tlsv1.2</protocols>
+service <verify>3</verify>
+ </ssl>
</transport>
</webui>
Let’s drop a bash script into the example to setup the TLS key config
$ cat ./setup.sh
#!/bin/bash
# generate two root CA private key and certificate (PKCS#8 encoded)
openssl req -x509 -newkey rsa:2048 -nodes -subj "/CN=localhost" \
-keyout root-ca-key-1.pem -out root-ca-cert-1.pem
# generate PKCS#8 unencrypted private key, certificate request (CSR), and
# certificate
# private key
openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 \
-out localhost.key.pem
# certificate request
openssl req -new -sha256 -key localhost.key.pem -subj "/CN=localhost" \
-out localhost.csr.pem
# signed public key certificate
openssl x509 -req -CA root-ca-cert-1.pem -CAkey root-ca-key-1.pem \
-CAcreateserial -sha256 \
-in localhost.csr.pem -out localhost.cert.pem
# build the examples.confd/restconf/basic example
make clean all
# generate the TLS key config.
# See CONFD_DIR/src/confd/yang/tailf-tls.yang for details
echo "<?xml version=\"1.0\"?>
<config xmlns=\"http://tail-f.com/ns/config/1.0\">
<tls xmlns=\"http://tail-f.com/ns/tls\">
<certificate>
<cert-data>" > ./confd-cdb/tls_data_nopw.xml
cat localhost.cert.pem >> ./confd-cdb/tls_data_nopw.xml
echo " </cert-data>
</certificate>
<private-key>
<key-data>" >> ./confd-cdb/tls_data_nopw.xml
cat localhost.key.pem >> ./confd-cdb/tls_data_nopw.xml
echo " </key-data>
</private-key>
<ca-certificates>
<name>rsa-1</name>
<cacert-data>" >> ./confd-cdb/tls_data_nopw.xml
cat root-ca-cert-1.pem >> ./confd-cdb/tls_data_nopw.xml
echo " </cacert-data>
</ca-certificates>
</tls>
</config>" >> ./confd-cdb/tls_data_nopw.xml
# start ConfD
make start
# wait for ConfD to start
confd --wait-started
What happens if we run it?
$ ./setup.sh
Generating a RSA private key
...................................+++++
..............+++++
writing new private key to 'root-ca-key-1.pem'
-----
...+++++
......+++++
Signature ok
subject=/CN=localhost
Getting CA Private Key
rm -rf \
*.o *.a *.xso *.fxs *.xsd *.ccl \
*_proto.h \
./confd-cdb *.db aaa_cdb.* \
rollback*/rollback{0..999} rollback{0..999} \
cli-history \
host.key host.cert ssh-keydir \
*.log confderr.log.* \
etc *.access \
running.invalid global.data _tmp* local.data
a=dhcp-ann.yang; \
/Users/tailf/confd-7.2.1/bin/confdc -c -o dhcp.fxs `[ -e $a ] && echo "-a $a"` -- dhcp.yang
mkdir -p ./confd-cdb
cp /Users/tailf/confd-7.2.1/var/confd/cdb/aaa_init.xml ./confd-cdb
ln -s /Users/tailf/confd-7.2.1/etc/confd/ssh ssh-keydir
rm -f confd-cdb/dhcp_init.xml ; cp dhcp_init.xml confd-cdb/dhcp_init.xml
/Users/tailf/confd-7.2.1/bin/confdc --emit-h dhcp.h dhcp.fxs
cc -c -o actions.o actions.c -Wall -g -I/Users/tailf/confd-7.2.1/include -I/opt/local/include
cc -o actions actions.o /Users/tailf/confd-7.2.1/lib/libconfd.a -lpthread -lm -L/opt/local/lib
ld: warning: directory not found for option '-L/opt/local/lib'
Build complete
/Users/tailf/confd-7.2.1/bin/confd --stop || true
DEBUG EOF on socket to ConfD
killall actions || true
No matching processes belonging to you were found
/Users/tailf/confd-7.2.1/bin/confd -c confd.conf --addloadpath /Users/tailf/confd-7.2.1/etc/confd
/Users/tailf/confd-7.2.1/bin/confd_load -C dhcp_oper.xml
./actions &
TRACE Connected (maapi) to ConfD
TRACE MAAPI_LOAD_ALL_NS
TRACE MAAPI_LOAD_MNS_MAPS
TRACE MAAPI_LOAD_HASH_DB
TRACE Connected (dp) to ConfD
TRACE Received daemon id 0
TRACE Connected (dp) to ConfD
TRACE Picked up old user session: 12 for user:system ctx:system
TRACE Picked up old user session: 11 for user:system ctx:system
TRACE Picked up old user session: 10 for user:system ctx:system
TRACE Picked up old user session: 1 for user:system ctx:system
Quick sanity test: using the self-signed CA certificate and generating a client certificate from that CA certificate for “mutual” authentication.
$ openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 -out client.key.pem
$ openssl req -new -sha256 -key client.key.pem -subj "/CN=client" -out \
client.csr.pem
$ openssl x509 -req -CA root-ca-cert-1.pem -CAkey root-ca-key-1.pem \
-CAcreateserial -sha256 -in client.csr.pem -out client.cert.pem
$ curl -kivu admin:admin --cacert ./root-ca-cert-1.pem --key ./client.key.pem --cert ./client.cert.pem https://localhost:8888/restconf/data/dhcpd:dhcp
* Expire in 0 ms for 6 (transfer 0x55b3a1704f50)
* Expire in 1 ms for 1 (transfer 0x55b3a1704f50)
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Expire in 0 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 1 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 0 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 0 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 1 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 0 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 0 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 1 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 0 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 0 ms for 1 (transfer 0x55b3a1704f50)
* Expire in 0 ms for 1 (transfer 0x55b3a1704f50)
* Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 150000 ms for 3 (transfer 0x55b3a1704f50)
* Expire in 200 ms for 4 (transfer 0x55b3a1704f50)
* Connected to localhost (127.0.0.1) port 8888 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: ./root-ca-cert-1.pem
CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [87 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [701 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [401 bytes data]
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
{ [58 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
} [1482 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [138 bytes data]
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
} [264 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=localhost
* start date: Apr 15 15:54:35 2020 GMT
* expire date: May 15 15:54:35 2020 GMT
* issuer: CN=localhost
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* Server auth using Basic with user 'admin'
} [5 bytes data]
> GET /restconf/data/dhcpd:dhcp HTTP/1.1
> Host: localhost:8888
> Authorization: Basic YWRtaW46YWRtaW4=
> User-Agent: curl/7.64.0
> Accept: application/yang-data+xml
>
{ [5 bytes data]
< HTTP/1.1 200 OK
< Date: Wed, 15 Apr 2020 15:54:38 GMT
< Last-Modified: Wed, 15 Apr 2020 15:54:38 GMT
< Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
< Etag: "1586-966078-493561"
< Content-Type: application/yang-data+xml
< Transfer-Encoding: chunked
< Pragma: no-cache
< Content-Security-Policy: default-src 'self'; block-all-mixed-content; base-uri 'self'; frame-ancestors 'none';
< Strict-Transport-Security: max-age=15552000; includeSubDomains
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
<
{ [5 bytes data]
HTTP/1.1 200 OK
100 58 0 58 0 0 753 0 --:--:-- --:--:-- --:--:-- 753
Date: Wed, 15 Apr 2020 15:54:38 GMT
* Connection #0 to host localhost left intact
Last-Modified: Wed, 15 Apr 2020 15:54:38 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Etag: "1586-966078-493561"
Content-Type: application/yang-data+xml
Transfer-Encoding: chunked
Pragma: no-cache
Content-Security-Policy: default-src 'self'; block-all-mixed-content; base-uri 'self'; frame-ancestors 'none';
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
<dhcp xmlns="http://yang-central.org/ns/example/dhcp" xmlns:dhcp="http://yang-central.org/ns/example/dhcp">
<max-lease-time>7200</max-lease-time>
<default-lease-time>600</default-lease-time>
<subnet>
<net>10.254.239.0/27</net>
<range>
<dynamic-bootp/>
<low>10.254.239.10</low>
<high>10.254.239.20</high>
</range>
<dhcp-options>
<router>rtr-239-0-1.example.org</router>
<router>rtr-239-0-2.example.org</router>
</dhcp-options>
<max-lease-time>1200</max-lease-time>
</subnet>
<shared-networks>
<shared-network>
<name>224-29</name>
<subnet>
<net>10.0.29.0/24</net>
<range>
<low>10.0.29.10</low>
<high>10.0.29.230</high>
</range>
<dhcp-options>
<router>rtr-29.example.org</router>
</dhcp-options>
</subnet>
<subnet>
<net>10.17.224.0/24</net>
<range>
<low>10.17.224.10</low>
<high>10.17.224.250</high>
</range>
<dhcp-options>
<router>rtr-224.example.org</router>
</dhcp-options>
</subnet>
</shared-network>
</shared-networks>
<status>
<leases>
<address>10.254.239.10</address>
<hardware>
<type>ethernet</type>
<address>01:21:53:a1:1a:23</address>
</hardware>
</leases>
<leases>
<address>10.254.239.12</address>
<hardware>
<type>ethernet</type>
<address>01:21:53:a1:1a:43</address>
</hardware>
</leases>
</status>
</dhcp>
* Connection #0 to host localhost left intact
1 Like
UPDATE: A demo project can be found here: https://github.com/ConfD-Developer/ConfD-Demos/tree/master/tls-restconf