SZTPD is an implementation of a “bootstrap server”, as defined in the Terminology section of RFC 8572, also known as an “SZTP server”, as defined in the Terminology section of draft-kwatsen-netconf-sztp- csr".
SZTPD is provided as software, an asynchronous event-driven Python-based executable. SZTPD is an application (not a library) that includes a northbound API for configuration, a southbound API for device bootstrapping requests, and eastbound hooks for integration with other business systems.
This documentation is in preparation for a “1.0.0” release, using the common “major.minor.patch” semantic versioning convention.
The following picture illustrates the API interfaces implemented by SZTPD:
The various aspects of this picture are discussed in the following sections.
The Northbound Interface (NBI) API is the largest API presented by SZTPD. The NBI is the interface enabling the setting of configuration, the viewing of operational state, and the reception of notifications (both system events and bootstrapping progress reports).
The NBI is a RESTCONF RFC 8040 based API that implements one of the three YANG modules:
where ‘1’ and ‘x’ refer to the SZTPD product mode. Each product mode has a distinct (though highly related) data model for the NBI.
The scope of the NBI is extended to also include the outbound interface SZTPD uses to deliver notifications to northbound controller/NMS applications (i.e., implementing a “receive-notification” HTTP POST request.
The data-model for the “receive-notification” request is formally defined in the YANG module “wn-sztp-callbacks” for specification purpose only. It does not imply that the northbound controller/NMS application must implement RESTCONF. Integrating applications only need to implement support for a single HTTP POST request (“bootstrap-complete”).
See the Northbound Interface section for more information about the NBI.
The southbound interface (SBI) implements the bootstrap server API defined in Section 7 of RFC 8572.
The SBI is a RESTCONF RFC 8040 based API that implements the “ietf-sztp-bootstrap-server” YANG module.
The SBI is fully described in Section 7 of RFC 8572.
Device-agent developers need to be aware that SZTPD currently only returns, in its get-bootstrapping-data
RPC-reply, CMS structures that are neither signed nor encrypted, but these are planning to be supported in upcoming releases of SZTPD. It is strongly suggested that the CMS-processing code switches on the top-most content-type’s OID:
SZTPD’s SBI is unaffected by SZTPD product modes.
The so called “eastbound” API is for product integration into backend business systems. The Eastbound API is unaffected by the product mode (‘1’ or ‘x’) SZTPD is using.
Three API integration points are defined. These API points enable SZTPD to:
Please see each section linked above for details.
This section presents a few examples illustrating some common interactions with SZTPD.
These examples use the ubiquitous curl
command line utility program for illustration purposes only. It is expected that production code would use a programming language to achieve the same result.
These examples assume a freshly installed SZTPD, i.e., using the default values described in “Defaults” section in the Installation Guide. To run a fresh instance of SZTPD, in one window, run the following command:
$ export SZTPD_INIT_MODE=1; sztpd sqlite:///:memory:
RFC 8040 defines a discovery protocol for determining a RESTCONF server’s root resource location. Note that SZTPD uses /restconf
as the default root resource location. No “Content-Type” is required for this resource.
Request:
$ curl -i http://127.0.0.1:8080/.well-known/host-meta
Response:
HTTP/1.1 200 OK
Server: <redacted>
Content-Type: application/xrd+xml; charset=utf-8
Content-Length: 104
Date: Thu, 23 Jan 2020 19:49:23 GMT
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Link rel="restconf" href="/restconf"/>
</XRD>
The NBI only supports JSON, while the SBI supports both XML and JSON.
This can be detemined by sending an HTTP “GET” operation to the RESTCONF Root location, discovered in the previous step, with no “Accept” type specified:
Request:
$ curl -i http://127.0.0.1:8080/restconf
Response:
HTTP/1.1 400 Bad Request
Accept: application/yang-data+json
Accept-Charset: utf-8
Content-Type: text/plain; charset=utf-8
Server: <redacted>
Content-Length: 191
Date: Tue, 15 Dec 2020 20:01:03 GMT
Unable to determine response encoding. An "Accept" value must be specified for
this resource. The "Accept" value must be "application/yang-data+json".
RFC 8040 defines an ability to query the RESTCONF server’s root resource to determine, for instance, what yang-library version it is using.
Request:
$ curl -i -H "Accept:application/yang-data+json" http://127.0.0.1:8080/restconf/
Response:
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Server: <redacted>
Content-Length: 137
Date: Tue, 15 Dec 2020 20:00:11 GMT
{
"ietf-restconf:restconf" : {
"data" : {},
"operations" : {},
"yang-library-version" : "2019-01-04"
}
}
The YANG Library is described in RFC 8525. RESTCONF clients may use it to understand what schema the connected server implements, which varies by the ‘use-for’ node in the Transport configuration.
Knowing the schema implemented is important to developer understanding SZTPD’s various APIs. This is especially true for the ‘native’ and ‘tenant’ interface’ types. These interface types present SZTPD’s Northbound API.
Note that, for understanding the ‘rfc8572’ interface type presented by SZTPD’s Southbound API, section 7 of RFC 8572 in highly recommended.
The following request shows that the ‘wn-sztpd-1’ YANG module is “implemented”. Had we chosen mode ‘x’ when the sztpd
process was started in the Getting Started section, then ‘wn-sztpd-1’ would be “imported” while ‘wn-sztpd-x’ would be “implemented”.
Note that the ‘tenant’ interface type is effectively the ‘wn-sztpd-1’ with the ‘system-level-administration-disabled’ feature set.
Request:
$ curl -i -H "Accept:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library
Response:
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 6105
Date: Thu, 14 Jan 2021 22:54:28 GMT
Server: <redacted>
{
"ietf-yang-library:modules-state": {
"module-set-id": "TBD",
"module": [
{
"name": "ietf-yang-types",
"revision": "2013-07-15",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-yang-types",
"conformance-type": "import"
},
{
"name": "ietf-inet-types",
"revision": "2013-07-15",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types",
"conformance-type": "import"
},
{
"name": "ietf-datastores",
"revision": "2018-02-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-yang-datastores",
"conformance-type": "import"
},
{
"name": "ietf-yang-library",
"revision": "2019-01-04",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-yang-library",
"conformance-type": "import"
},
{
"name": "iana-crypt-hash",
"revision": "2014-08-06",
"namespace": "urn:ietf:params:xml:ns:yang:iana-crypt-hash",
"conformance-type": "import"
},
{
"name": "ietf-x509-cert-to-name",
"revision": "2014-12-10",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name",
"conformance-type": "implement"
},
{
"name": "ietf-restconf",
"revision": "2017-01-26",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-restconf",
"conformance-type": "implement"
},
{
"name": "ietf-netconf-acm",
"revision": "2018-02-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-acm",
"conformance-type": "import"
},
{
"name": "ietf-sztp-conveyed-info",
"revision": "2019-04-30",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-sztp-conveyed-info",
"conformance-type": "implement"
},
{
"name": "ietf-crypto-types",
"revision": "2021-01-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-crypto-types",
"conformance-type": "implement"
},
{
"name": "ietf-truststore",
"revision": "2021-01-14",
"feature": [
"certificates"
],
"namespace": "urn:ietf:params:xml:ns:yang:ietf-truststore",
"conformance-type": "import"
},
{
"name": "ietf-keystore",
"revision": "2021-01-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-keystore",
"conformance-type": "import"
},
{
"name": "ietf-tcp-common",
"revision": "2021-01-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-tcp-common",
"conformance-type": "import"
},
{
"name": "ietf-tcp-client",
"revision": "2021-01-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-tcp-client",
"conformance-type": "import"
},
{
"name": "ietf-tcp-server",
"revision": "2021-01-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-tcp-server",
"conformance-type": "import"
},
{
"name": "ietf-tls-common",
"revision": "2021-01-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-tls-common",
"conformance-type": "import"
},
{
"name": "ietf-tls-client",
"revision": "2021-01-14",
"feature": [
"x509-certificate-auth",
"client-auth-config-supported"
],
"namespace": "urn:ietf:params:xml:ns:yang:ietf-tls-client",
"conformance-type": "import"
},
{
"name": "ietf-tls-server",
"revision": "2021-01-14",
"feature": [
"x509-certificate-auth",
"client-auth-config-supported"
],
"namespace": "urn:ietf:params:xml:ns:yang:ietf-tls-server",
"conformance-type": "import"
},
{
"name": "ietf-http-client",
"revision": "2021-01-14",
"feature": [
"basic-auth"
],
"namespace": "urn:ietf:params:xml:ns:yang:ietf-http-client",
"conformance-type": "import"
},
{
"name": "ietf-http-server",
"revision": "2021-01-14",
"namespace": "urn:ietf:params:xml:ns:yang:ietf-http-server",
"conformance-type": "import"
},
{
"name": "ietf-restconf-client",
"revision": "2021-01-14",
"feature": [
"https-initiate"
],
"namespace": "urn:ietf:params:xml:ns:yang:ietf-restconf-client",
"conformance-type": "import"
},
{
"name": "ietf-restconf-server",
"revision": "2021-01-14",
"feature": [
"http-listen",
"https-listen"
],
"namespace": "urn:ietf:params:xml:ns:yang:ietf-restconf-server",
"conformance-type": "import"
},
{
"name": "wn-x509-c2n",
"revision": "2021-01-14",
"namespace": "https://watsen.net/wnc2n",
"conformance-type": "implement"
},
{
"name": "wn-app-rpcs",
"revision": "2021-01-14",
"namespace": "https://watsen.net/app-rpcs",
"conformance-type": "implement"
},
{
"name": "wn-app",
"revision": "2021-01-14",
"namespace": "https://watsen.net/wnapp",
"feature": [
],
"conformance-type": "import"
},
{
"name": "wn-sztpd-rpcs",
"revision": "2021-01-14",
"namespace": "https://watsen.net/sztpd-rpcs",
"conformance-type": "implement"
},
{
"name": "wn-sztpd-0",
"revision": "2021-01-14",
"feature": [
"onboarding-supported"
],
"namespace": "https://watsen.net/sztpd-0",
"conformance-type": "import"
},
{
"name": "wn-sztpd-1",
"revision": "2021-01-14",
"feature": [
"device-ownership-verification"
],
"namespace": "https://watsen.net/sztpd-1",
"conformance-type": "implement"
}
]
}
}
Request:
$ curl -i -H "Accept:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:running
Response:
HTTP/1.1 200 OK
Server: <redacted>
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 486
Date: Thu, 23 Jan 2020 19:55:47 GMT
{
"wn-sztpd-1:transport": {
"listen": {
"endpoint": [
{
"name": "default startup endpoint",
"use-for": "native-interface",
"http": {
"tcp-server-parameters": {
"local-address": "127.0.0.1"
}
}
}
]
}
}
}
As was mentioned previously, a freshly installed SZTPD has no administrator account configured, and yet it requires one, and thus the first write operation to a freshly installed SZTPD instance must configure at least one administrator account. The following illustrates this using a POST request.
Request:
$ cat admin_accounts.json
{
"wn-sztpd-1:admin-accounts":{
"admin-account": [
{
"email-address": "my-admin@example.com",
"password": "$0$my-secret",
"access": "unrestricted"
}
]
}
}
$ curl -i -X POST --data @admin_accounts.json -H "Content-Type:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:running
Response:
HTTP/1.1 201 Created
Server: <redacted>
Content-Length: 0
Content-Type: application/octet-stream
Date: Thu, 23 Jan 2020 20:19:27 GMT
Request:
cat device-types.json
{
"wn-sztpd-1:device-types": {
"device-type": [
{
"name": "my-device-type"
}
]
}
}
$ curl -i -X POST --data @device-types.json -H "Content-Type:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:running
Response:
HTTP/1.1 401 Unauthorized
Server: <redacted>
Content-Length: 0
Content-Type: application/octet-stream
Date: Thu, 23 Jan 2020 20:24:21 GMT
Again, but this time with authentication!
Request:
[Note: '\' line wrapping per RFC 8792]
$ curl -i -X POST --user my-admin@example.com:my-secret --data @device-types.json \
-H "Content-Type:application/yang-data+json" http://127.0.0.1:8080/restconf/ds/ietf-datastores:running
Response:
HTTP/1.1 201 Created
Server: <redacted>
Content-Length: 0
Content-Type: application/octet-stream
Date: Thu, 23 Jan 2020 20:29:19 GMT
Alert: be mindful that this example uses the mode-1 schema, and each YANG schema has different ways to configured devices (i.e., if there is a list of devices under the “/tenants/tenant” tree).
Request:
[Note: '\' line wrapping per RFC 8792]
$ cat devices.json
{
"wn-sztpd-1:devices": {
"device": [
{
"serial-number": "my-serial-number",
"device-type": "my-device-type",
"activation-code": "$0$my-secret"
}
]
}
}
$ curl -i -X POST --user my-admin@example.com:my-secret --data @devices.json \
-H "Content-Type:application/yang-data+json" http://127.0.0.1:8080/restconf/ds/ietf-datastores:running
Response:
HTTP/1.1 201 Created
Server: <redacted>
Content-Length: 0
Content-Type: application/octet-stream
Date: Thu, 23 Jan 2020 20:32:23 GMT
When initializing a fresh system, it is often easiest to replace the entire contents of the SZTPD running
configuration with a single request to the server.
The following single PUT achieves the same result as all of the above commands combined.
Note that the system-provided default ‘/transport’ node is included in the PUT as well, as otherwise the system will complain that it’s being deleted.
Request:
$ cat running.json
{
"wn-sztpd-1:transport": {
"listen": {
"endpoint": [
{
"name": "default startup endpoint",
"use-for": "native-interface",
"http": {
"tcp-server-parameters": {
"local-address": "127.0.0.1"
}
}
}
]
}
},
"wn-sztpd-1:admin-accounts":{
"admin-account": [
{
"email-address": "my-admin@example.com",
"password": "$0$my-secret",
"access": "unrestricted"
}
]
},
"wn-sztpd-1:device-types": {
"device-type": [
{
"name": "my-device-type"
}
]
},
"wn-sztpd-1:devices": {
"device": [
{
"serial-number": "my-serial-number",
"device-type": "my-device-type",
"activation-code": "$0$my-secret"
}
]
}
}
$ curl -i -X PUT --data @running.json -H "Content-Type:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:running
Response:
HTTP/1.1 204 No Content
Server: <redacted>
Content-Length: 0
Content-Type: application/octet-stream
Date: Thu, 23 Jan 2020 20:41:54 GMT
A production deployment must use TLS to protect the RESTCONF resources.
This section shows how to configure SZTPD to have:
For running code, please see the Simulator code.
This section uses scripts to generate its contents. These scripts use a PKI that has been instantiated as “pki” in the current directory. This ‘pki’ directory is the same as that in the Simulator code. These scripts could be run out of that directory, after creating an empty directory called “output”.
The code below uses a sed
script to replace placeholder values in a template to produce the configuration sent by PUT. These values are defined as follows:
Variable | Description |
---|---|
NBI_PORT | The port that the ‘native’ interface listens on |
SBI_PORT | The port that the ‘rfc8572’ interface listens on |
NBI_PRI_KEY_B64 | The base64 encoding of the server’s NBI private key. |
NBI_PUB_KEY_B64 | The base64 encoding of the server’s NBI public key. |
NBI_EE_CERT_B64 | The base64 encoding of the server’s NBI end-entity cert. |
SBI_PRI_KEY_B64 | The base64 encoding of the server’s SBI private key. |
SBI_PUB_KEY_B64 | The base64 encoding of the server’s SBI public key. |
SBI_EE_CERT_B64 | The base64 encoding of the server’s SBI end-entity cert. |
These are the base64 of the DER (not the PEM), that is, the header and footer =====
lines are missing, and all the B64 characters are on one line.
The private and public key values are the native OpenSSL values for private and public keys.
The certificate values are the degenerate form of a CMS (PKCS #7) commonly used to communicate a chain of certificates.
Script:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
OPENSSL="openssl"
TEMPDIR=`mktemp -d`
# NBI Port
NBI_PORT="8080"
NBI_PRI_KEY_B64=`$OPENSSL enc -base64 -A -in pki/sztpd1/nbi/end-entity/private_key.der`
NBI_PUB_KEY_B64=`$OPENSSL enc -base64 -A -in pki/sztpd1/nbi/end-entity/public_key.der`
cat pki/sztpd1/nbi/end-entity/my_cert.pem pki/sztpd1/nbi/intermediate2/my_cert.pem > $TEMPDIR/cert_chain.pem
$OPENSSL crl2pkcs7 -nocrl -certfile $TEMPDIR/cert_chain.pem -outform DER -out $TEMPDIR/cert_chain.cms
NBI_EE_CERT_B64=`$OPENSSL enc -base64 -A -in $TEMPDIR/cert_chain.cms`
# SBI Port
SBI_PORT="9090"
SBI_PRI_KEY_B64=`$OPENSSL enc -base64 -A -in pki/sztpd1/sbi/end-entity/private_key.der`
SBI_PUB_KEY_B64=`$OPENSSL enc -base64 -A -in pki/sztpd1/sbi/end-entity/public_key.der`
cat pki/sztpd1/sbi/end-entity/my_cert.pem pki/sztpd1/sbi/intermediate2/my_cert.pem > $TEMPDIR/cert_chain.pem
$OPENSSL crl2pkcs7 -nocrl -certfile $TEMPDIR/cert_chain.pem -outform DER -out $TEMPDIR/cert_chain.cms
SBI_EE_CERT_B64=`$OPENSSL enc -base64 -A -in $TEMPDIR/cert_chain.cms`
# client cert (DevID) trust anchor
cat pki/client/root-ca/my_cert.pem pki/client/intermediate1/my_cert.pem pki/client/intermediate2/my_cert.pe\
m > $TEMPDIR/ta_cert_chain.pem
$OPENSSL crl2pkcs7 -nocrl -certfile $TEMPDIR/ta_cert_chain.pem -outform DER -out $TEMPDIR/ta_cert_chain.cms
CLIENT_CERT_TA_B64=`$OPENSSL enc -base64 -A -in $TEMPDIR/ta_cert_chain.cms`
# initialize body for the PUT request
cat << EOM > $TEMPDIR/running.json
{
"wn-sztpd-1:transport": {
"listen": {
"endpoint": [
{
"name": "native-interface",
"use-for": "native-interface",
"https": {
"tcp-server-parameters": {
"local-address": "127.0.0.1",
"local-port": $NBI_PORT
},
"tls-server-parameters": {
"server-identity": {
"certificate" : {
"reference": {
"asymmetric-key": "nbi-server-end-entity-key",
"certificate": "nbi-server-end-entity-cert"
}
}
}
}
}
},
{
"name": "rfc8572-interface",
"use-for": "rfc8572-interface",
"https": {
"tcp-server-parameters": {
"local-address": "127.0.0.1",
"local-port": $SBI_PORT
},
"tls-server-parameters": {
"server-identity": {
"certificate" : {
"reference": {
"asymmetric-key": "sbi-server-end-entity-key",
"certificate": "sbi-server-end-entity-cert"
}
}
},
"client-authentication": {
"ca-certs": {
"local-truststore-reference": "my-device-identity-ca-certs"
}
}
}
}
}
]
}
},
"wn-sztpd-1:admin-accounts": {
"admin-account": [
{
"email-address": "my-admin@example.com",
"password": "\$0\$my-secret",
"access": "unrestricted"
}
]
},
"wn-sztpd-1:keystore": {
"asymmetric-keys": {
"asymmetric-key": [
{
"name": "nbi-server-end-entity-key",
"public-key-format": "ietf-crypto-types:subject-public-key-info-format",
"public-key": "$NBI_PUB_KEY_B64",
"private-key-format": "ietf-crypto-types:ec-private-key-format",
"cleartext-private-key": "$NBI_PRI_KEY_B64",
"certificates": {
"certificate": [
{
"name": "nbi-server-end-entity-cert",
"cert-data": "$NBI_EE_CERT_B64"
}
]
}
},
{
"name": "sbi-server-end-entity-key",
"public-key-format": "ietf-crypto-types:subject-public-key-info-format",
"public-key": "$SBI_PUB_KEY_B64",
"private-key-format": "ietf-crypto-types:ec-private-key-format",
"cleartext-private-key": "$SBI_PRI_KEY_B64",
"certificates": {
"certificate": [
{
"name": "sbi-server-end-entity-cert",
"cert-data": "$SBI_EE_CERT_B64"
}
]
}
}
]
}
},
"wn-sztpd-1:truststore": {
"certificate-bags": {
"certificate-bag": [
{
"name": "my-device-identity-ca-certs",
"description": "A set of TA certs used to authenticate device client certs.",
"certificate": [
{
"name": "my-device-identity-ca-cert-circa-2020",
"cert-data": "$CLIENT_CERT_TA_B64"
}
]
}
]
}
},
"wn-sztpd-1:device-types": {
"device-type": [
{
"name": "my-device-type",
"identity-certificates": {
"verification": {
"local-truststore-reference": {
"certificate-bag": "my-device-identity-ca-certs",
"certificate": "my-device-identity-ca-cert-circa-2020"
}
},
"serial-number-extraction": "wn-x509-c2n:serial-number"
}
}
]
},
"wn-sztpd-1:devices": {
"device": [
{
"serial-number": "my-serial-number",
"device-type": "my-device-type",
"activation-code": "\$0\$my-secret"
}
]
}
}
EOM
# PUT running
curl -i -X PUT --data @$TEMPDIR/running.json -H "Content-Type:application/yang-data+json" http://127.0.0.1:\
8080/restconf/ds/ietf-datastores:running 1> output/put_running.out 2> /dev/null
rm -rf "$TEMPDIR"
Output:
HTTP/1.1 100 Continue
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:01 GMT
Server: <redacted>
Since this change modifies the “/transport” tree, the SZTPD instance sends a SIGHUP to itself, thus causing it to reload the configuration and re-open listening ports per configuration.
SZTPD takes about 2 seconds to reload with a relatively empty configuration. Once sufficient time has elapsed (a few seconds), the configured ports will be available.
Below we first use the wrong URL scheme “http”, and then correct it to “https”, and then, finally, add the missing “–cacert” parameter. All these commands use “HEAD” against yang-library.
================================== NOTE: '\\' line wrapping per RFC 8792 ===================================
#!/bin/sh
printf "=== Output from NBI Port ===\n" 1> output/get_yang_library.out
printf "\n1) Incorrect 'http' (should be 'https'):\n\n" 1>> output/get_yang_library.out
curl -i --head --user my-admin@example.com:my-secret -H "Accept:application/yang-data+json" http://127.0.0.\
\1:8080/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library &> temp.out
sed -n '/curl/,$p' temp.out 1>> output/get_yang_library.out
printf "\n2) Correct 'https' (but missing '--cacert'):\n\n" 1>> output/get_yang_library.out
curl -i --head --user my-admin@example.com:my-secret -H "Accept:application/yang-data+json" https://127.0.0\
\.1:8080/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library &> temp.out
sed -n '/curl/,$p' temp.out 1>> output/get_yang_library.out
printf "\n3) Correct 'https' and '--cacert':\n\n" 1>> output/get_yang_library.out
curl -i --head --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret -H "Accept:application/ya\
\ng-data+json" https://127.0.0.1:8080/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-librar\
\y 1>> output/get_yang_library.out 2> /dev/null
printf "\n\n=== Output from SBI Port ===\n" 1>> output/get_yang_library.out
printf "\n1) Incorrect 'http' (should be 'https') [also note 'my-serial-number']:\n\n" 1>> output/get_yang\
\_library.out
curl -i --head --user my-serial-number:my-secret -H "Accept:application/yang-data+json" http://127.0.0.1:90\
\90/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library &> temp.out
sed -n '/curl/,$p' temp.out 1>> output/get_yang_library.out
printf "\n2) Correct 'https' (but missing '--cacert'):\n\n" 1>> output/get_yang_library.out
curl -i --head --user my-serial-number:my-secret -H "Accept:application/yang-data+json" https://127.0.0.1:9\
\090/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library &> temp.out
sed -n '/curl/,$p' temp.out 1>> output/get_yang_library.out
printf "\n3) Correct 'https' and '--cacert' (but missing '--key' and '--cert'):\n\n" 1>> output/get_yang_li\
\brary.out
curl -i --head --cacert sbi_trust_chain.pem --user my-serial-number:my-secret -H "Accept:application/yang-d\
\ata+json" https://127.0.0.1:9090/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library 1>\
\> output/get_yang_library.out 2> /dev/null
printf "\n4) Correct 'https', '--cacert', '--key', and '--cert':\n\n" 1>> output/get_yang_library.out
curl -i --head --cacert sbi_trust_chain.pem --key pki/client/end-entity/private_key.pem --cert pki/client/e\
\nd-entity/my_cert.pem --user my-serial-number:my-secret -H "Accept:application/yang-data+json" https://127\
\.0.0.1:9090/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library 1>> output/get_yang_lib\
\rary.out 2> /dev/null
# cleanup
rm temp.out
Output:
=== Output from NBI Port ===
1) Incorrect 'http' (should be 'https'):
curl: (52) Empty reply from server
2) Correct 'https' (but missing '--cacert'):
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
3) Correct 'https' and '--cacert':
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 6105
Date: Fri, 15 Jan 2021 02:38:06 GMT
Server: <redacted>
=== Output from SBI Port ===
1) Incorrect 'http' (should be 'https') [also note 'my-serial-number']:
curl: (52) Empty reply from server
2) Correct 'https' (but missing '--cacert'):
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
3) Correct 'https' and '--cacert' (but missing '--key' and '--cert'):
HTTP/1.1 401 Unauthorized
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 143
Date: Fri, 15 Jan 2021 02:38:07 GMT
Server: <redacted>
4) Correct 'https', '--cacert', '--key', and '--cert':
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 1967
Date: Fri, 15 Jan 2021 02:38:07 GMT
Server: <redacted>
This command fails because no “responses” have been configured for the device on the server. Note that error code 404 is used to indicate that the device may try again.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.json
{
"ietf-sztp-bootstrap-server:input" : {
"hw-model" : "model-x",
"os-name" : "vendor-os",
"os-version" : "17.3R2.1",
"nonce" : "BASE64VALUE="
}
}
EOM
# POST 'input' for the "get-bootstrapping-data" RPC resource
curl -i -X POST --data @input.json -H "Content-Type:application/yang-data+json" --cacert sbi_trust_chain.pe\
m --key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-num\
ber:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data \
1> output/post_rpc_input.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_rpc_input.out
# cleanup
rm -f input.json
Output:
HTTP/1.1 404 Not Found
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 198
Date: Fri, 15 Jan 2021 02:38:07 GMT
Server: <redacted>
{
"ietf-restconf:errors": {
"error": [
{
"error-type": "application",
"error-tag": "data-missing",
"error-message": "No responses configured."
}
]
}
}
Configure the ‘/bootstrapping-servers’ node. This list contains all ‘bootstrap-server’ definitions, an ordered subset of which may be referenced by subsequent steps. Note that the port
and trust-anchor
nodes are replaced by variables.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
OPENSSL="openssl"
# generate values for placeholders
cat pki/sztpd2/sbi/root-ca/my_cert.pem pki/sztpd2/sbi/intermediate1/my_cert.pem > cert_chain.pem
$OPENSSL crl2pkcs7 -nocrl -certfile cert_chain.pem -outform DER -out cert_chain.cms
BOOTSVR_TA_CERT_B64=`$OPENSSL enc -base64 -A -in cert_chain.cms`
# initialize body for the POST request
cat << EOM > bootstrap-servers.json
{
"wn-sztpd-1:bootstrap-servers": {
"bootstrap-server": [
{
"name": "my-bootstrap-server",
"address": "127.0.0.1",
"port": 9443,
"trust-anchor": "$BOOTSVR_TA_CERT_B64"
}
]
}
}
EOM
# POST 'bootstrap-servers' to running
curl -i -X POST --data @bootstrap-servers.json -H "Content-Type:application/yang-data+json" --cacert nbi_tr\
ust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/restconf/ds/ietf-datastores:runn\
ing 1> output/post_bootstrap_servers.out 2>/dev/null
# cleanup
rm -f bootstrap-servers.json
rm -f cert_chain.pem
rm -f cert_chain.cms
Output:
HTTP/1.1 100 Continue
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:08 GMT
Server: <redacted>
Configure the ‘/conveyed-information-responses’ node. Configure a ‘my-redirect-information’ to return ‘my-bootstrap-server’. An ordered list of bootstrap servers may be configured.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
OPENSSL="openssl"
# initialize body for the POST request
cat << EOM > conveyed-information-responses.json
{
"wn-sztpd-1:conveyed-information-responses": {
"redirect-information-response": [
{
"name": "my-redirect-information",
"redirect-information": {
"bootstrap-server": [
"my-bootstrap-server"
]
}
}
]
}
}
EOM
# POST 'conveyed-information-responses' to running
curl -i -X POST --data @conveyed-information-responses.json -H "Content-Type:application/yang-data+json" --\
cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/restconf/ds/ietf-da\
tastores:running 1> output/post_conveyed_information_responses.out 2>/dev/null
# cleanup
rm -f conveyed-information-responses.json
Output:
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:08 GMT
Server: <redacted>
Configure the ‘response-manager’ node inside the device object to return “my-redirect-information”. A “catch-all” rule (i.e., one without any ‘match-criteria’ defined) tells STZPD to return the just configured ‘my-redirect-information’.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize body for the POST request
cat << EOM > response-manager.json
{
"wn-sztpd-1:response-manager": {
"matched-response": [
{
"name": "catch-all-response",
"response": {
"conveyed-information": {
"redirect-information": {
"reference": "my-redirect-information"
}
}
}
}
]
}
}
EOM
# POST 'response-manager' to *device*
curl -i -X POST --data @response-manager.json -H "Content-Type:application/yang-data+json" --cacert nbi_tru\
st_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/restconf/ds/ietf-datastores:runni\
ng/wn-sztpd-1:devices/device=my-serial-number 1> output/post_response_manager.out 2>/dev/null
# cleanup
rm -f response-manager.json
Output:
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:08 GMT
Server: <redacted>
Accessing the get-bootstrapping-data
RPC on the SBI again, now it works.
Request: (Same as in the Simulate Device Trying to Get Bootstrapping Data section)
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.json
{
"ietf-sztp-bootstrap-server:input" : {
"hw-model" : "model-x",
"os-name" : "vendor-os",
"os-version" : "17.3R2.1",
"nonce" : "BASE64VALUE="
}
}
EOM
# POST 'input' for the "get-bootstrapping-data" RPC resource
curl -i -X POST --data @input.json -H "Content-Type:application/yang-data+json" --cacert sbi_trust_chain.pe\
m --key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-num\
ber:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data \
1> output/post_rpc_input.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_rpc_input.out
# cleanup
rm -f input.json
Output:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 2679
Date: Fri, 15 Jan 2021 02:38:09 GMT
Server: <redacted>
{
"ietf-sztp-bootstrap-server:output": {
"conveyed-information": "MIIHmQYLKoZIhvcNAQkQASugggeIBIIHhHsKICAiaWV0Zi1zenRwLWNvbnZleWVkLWluZm86cmVkaX\
JlY3QtaW5mb3JtYXRpb24iOiB7CiAgICAiYm9vdHN0cmFwLXNlcnZlciI6IFsKICAgICAgewogICAgICAgICJhZGRyZXNzIjogIjEyNy4wL\
jAuMSIsCiAgICAgICAgInBvcnQiOiA5NDQzLAogICAgICAgICJ0cnVzdC1hbmNob3IiOiAiTUlJRkVRWUpLb1pJaHZjTkFRY0NvSUlGQWpD\
Q0JQNENBUUV4QURBTEJna3Foa2lHOXcwQkJ3R2dnZ1RrTUlJQ1dqQ0NBZitnQXdJQkFnSUJBVEFLQmdncWhrak9QUVFEQWpCMU1Rc3dDUVl\
EVlFRR0V3SllXREVkTUJzR0ExVUVDQXdVVFhrZ1UzUmhkR1VnYjNJZ1VISnZkbWx1WTJVeEdEQVdCZ05WQkFvTUQwMTVJRTl5WjJGdWFYcG\
hkR2x2YmpFUU1BNEdBMVVFQ3d3SFRYa2dWVzVwZERFYk1Ca0dBMVVFQXd3U2MySnBMM05sY25abGNpOXliMjkwTFdOaE1DQVhEVEl3TURre\
E9ESXdNVGswTkZvWUR6azVPVGt4TWpNeE1qTTFPVFU1V2pCMU1Rc3dDUVlEVlFRR0V3SllXREVkTUJzR0ExVUVDQXdVVFhrZ1UzUmhkR1Vn\
YjNJZ1VISnZkbWx1WTJVeEdEQVdCZ05WQkFvTUQwMTVJRTl5WjJGdWFYcGhkR2x2YmpFUU1BNEdBMVVFQ3d3SFRYa2dWVzVwZERFYk1Ca0d\
BMVVFQXd3U2MySnBMM05sY25abGNpOXliMjkwTFdOaE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTB1REM5ZFZMWklOSW\
5OK3hKdG9HWmtGTmUxVU9YWk1LSmFVV0VidXFoM1VMWjA1dWdFRmRIVmc1WklzR3BGWVdGV2VFMU8rTDJxUGJ3WUZpTFdjVHpLTitNSHd3S\
FFZRFZSME9CQllFRktoYjkyRlZEWnpCSnBoR2N5RC9XU0FvVVhZWU1Bd0dBMVVkRXdRRk1BTUJBZjh3RGdZRFZSMFBBUUgvQkFRREFnRUdN\
RDBHQTFVZEh3UTJNRFF3TXFBd29DNkdMR2gwZEhBNkx5OWpjbXd1WlhoaGJYQnNaUzVqYjIwL1kyRTljMkpwT25ObGNuWmxjanB5YjI5MEx\
XTmhNQW9HQ0NxR1NNNDlCQU1DQTBrQU1FWUNJUUNYdDg0Q0l6VGNlOWhLWnVYR2FKL1MxUDlZTExucTZ2RDJZbmI4aHVEUm9BSWhBSkVaNm\
pBbGJKamM5VVBWVEd5REVoSWc2a3N2Z1lIMS9ieUk5cVpxbEZ2Zk1JSUNnakNDQWlpZ0F3SUJBZ0lCQWpBS0JnZ3Foa2pPUFFRREFqQjFNU\
XN3Q1FZRFZRUUdFd0pZV0RFZE1Cc0dBMVVFQ0F3VVRYa2dVM1JoZEdVZ2IzSWdVSEp2ZG1sdVkyVXhHREFXQmdOVkJBb01EMDE1SUU5eVoy\
RnVhWHBoZEdsdmJqRVFNQTRHQTFVRUN3d0hUWGtnVlc1cGRERWJNQmtHQTFVRUF3d1NjMkpwTDNObGNuWmxjaTl5YjI5MExXTmhNQ0FYRFR\
Jd01Ea3hPREl3TVRrME5Wb1lEems1T1RreE1qTXhNak0xT1RVNVdqQjdNUXN3Q1FZRFZRUUdFd0pZV0RFZE1Cc0dBMVVFQ0F3VVRYa2dVM1\
JoZEdVZ2IzSWdVSEp2ZG1sdVkyVXhHREFXQmdOVkJBb01EMDE1SUU5eVoyRnVhWHBoZEdsdmJqRVFNQTRHQTFVRUN3d0hUWGtnVlc1cGRER\
WhNQjhHQTFVRUF3d1ljMkpwTDNObGNuWmxjaTlwYm5SbGNtMWxaR2xoZEdVeE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdB\
RXdPMlVmTDkxWnpNa3lZLzFJbi8zZDFDMkdINkwzcjFEU1BzZERNYWxsUkdJMlNMVUFNOXFEZENuZldvTVRydnBuYm5ldmo5cVF0R1pTbm8\
wc0dMU2I2T0JvRENCblRBZEJnTlZIUTRFRmdRVWlGc0dUVlJzZk00SWpoNGREelZtZ0NOUnFPc3dId1lEVlIwakJCZ3dGb0FVcUZ2M1lWVU\
5uTUVtbUVaeklQOVpJQ2hSZGhnd0RBWURWUjBUQkFVd0F3RUIvekFPQmdOVkhROEJBZjhFQkFNQ0FRWXdQUVlEVlIwZkJEWXdOREF5b0RDZ\
0xvWXNhSFIwY0RvdkwyTnliQzVsZUdGdGNHeGxMbU52YlQ5allUMXpZbWs2YzJWeWRtVnlPbkp2YjNRdFkyRXdDZ1lJS29aSXpqMEVBd0lE\
U0FBd1JRSWhBTmxQVDFwcERaMHBlczJTaC9qMklnNEFWQ01qQTVKRmxDYnJUQmo4MGtkSkFpQURDNWdFeFczWHFvRWJ6Sk0wMmxEVTdiSTJ\
GZGtXT2pWNnNFamk4MTd1WDZFQU1RQT0iCiAgICAgIH0KICAgIF0KICB9Cn0="
}
}
Now delete all of the above config to get back to baseline, needed for upcoming Configuring an Onboarding Response section.
Note that the configuration is removed in the opposite order to avoid SZTPD throwing a validation error due to dangling references.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# These are removed in opposite order to avoid dangling reference validation errors.
curl -i -X DELETE --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080\
/restconf/ds/ietf-datastores:running/wn-sztpd-1:devices/device=my-serial-number/response-manager 1> output/\
delete_redirect_info.out
curl -i -X DELETE --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080\
/restconf/ds/ietf-datastores:running/wn-sztpd-1:conveyed-information-responses 1>> output/delete_redirect_i\
nfo.out
curl -i -X DELETE --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080\
/restconf/ds/ietf-datastores:running/wn-sztpd-1:bootstrap-servers 1>> output/delete_redirect_info.out
Output:
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:09 GMT
Server: <redacted>
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:09 GMT
Server: <redacted>
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:09 GMT
Server: <redacted>
Configuring an onboarding response is done in much the same way, just with different nodes reflecting the difference between a “redirect” and an “onboarding” response.
First configure information about a hypothetical boot-image the device should be running:
================================== NOTE: '\\' line wrapping per RFC 8792 ===================================
#!/bin/sh
OPENSSL="openssl"
# initialize body for the POST request
dd if=/dev/urandom of=my-boot-image.img bs=64k count=1 >> /dev/null 2>&1
BOOT_IMG_HASH_VAL=`$OPENSSL dgst -sha256 -c my-boot-image.img | awk '{print $2}'`
cat << EOM > boot-images.json
{
"wn-sztpd-1:boot-images": {
"boot-image": [
{
"name": "my-boot-image.img",
"download-uri": [ "https://example.com/my-boot-image.img" ],
"image-verification": [
{
"hash-algorithm": "ietf-sztp-conveyed-info:sha-256",
"hash-value": "$BOOT_IMG_HASH_VAL"
}
]
}
]
}
}
EOM
# POST 'boot-images' to running
curl -i -X POST --data @boot-images.json -H "Content-Type:application/yang-data+json" --cacert nbi_trust_ch\
\ain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/restconf/ds/ietf-datastores:running 1\
\> output/post_boot_images.out 2>/dev/null
rm -rf my-boot-image.img boot-images.json
Output:
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:09 GMT
Server: <redacted>
Configure information about the “pre” and “post” scripts the device should run:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
OPENSSL="openssl"
# encode a pre-configuration script
cat << EOM > my-pre-configuration-script
#/bin/bash
echo "inside the pre-configuration-script..."
EOM
PRE_SCRIPT_B64=`$OPENSSL enc -base64 -A -in my-pre-configuration-script`
# encode a post-configuration script
cat << EOM > my-post-configuration-script
#/bin/bash
echo "inside the post-configuration-script..."
EOM
POST_SCRIPT_B64=`$OPENSSL enc -base64 -A -in my-post-configuration-script`
# initialize body for the POST request
cat << EOM > scripts.json
{
"wn-sztpd-1:scripts": {
"pre-configuration-script": [
{
"name": "my-pre-configuration-script",
"script": "$PRE_SCRIPT_B64"
}
],
"post-configuration-script": [
{
"name": "my-post-configuration-script",
"script": "$POST_SCRIPT_B64"
}
]
}
}
EOM
# POST 'scripts' to running
curl -i -X POST --data @scripts.json -H "Content-Type:application/yang-data+json" --cacert nbi_trust_chain.\
pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/restconf/ds/ietf-datastores:running 1> out\
put/post_scripts.out 2>/dev/null
# cleanup
rm -f scripts.json
rm -f my-pre-configuration-script
rm -f my-post-configuration-script
Output:
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:10 GMT
Server: <redacted>
Set the device-specific configuration the device should run:
================================== NOTE: '\\' line wrapping per RFC 8792 ===================================
#!/bin/sh
OPENSSL="openssl"
# initialize body for the POST request
cat << EOM > my-configuration
<top xmlns="https:/example.com/config">
<any-xml-content-okay/>
</top>
EOM
CONFIG_B64=`$OPENSSL enc -base64 -A -in my-configuration`
cat << EOM > configurations.json
{
"wn-sztpd-1:configurations": {
"configuration": [
{
"name": "my-configuration",
"configuration-handling": "merge",
"config": "$CONFIG_B64"
}
]
}
}
EOM
# POST 'configurations.json' to running
curl -i -X POST --data @configurations.json -H "Content-Type:application/yang-data+json" --cacert nbi_trust\
\_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/restconf/ds/ietf-datastores:runnin\
\g 1> output/post_configurations.out 2>/dev/null
# cleanup
rm -f my-configuration
rm -f configurations.json
Output:
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:10 GMT
Server: <redacted>
Configure “conveyed-information” referencing all of the above:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize body for the POST request
cat << EOM > conveyed-information-responses.json
{
"wn-sztpd-1:conveyed-information-responses": {
"onboarding-information-response": [
{
"name": "my-onboarding-information",
"onboarding-information": {
"boot-image": "my-boot-image.img",
"pre-configuration-script": "my-pre-configuration-script",
"configuration": "my-configuration",
"post-configuration-script": "my-post-configuration-script"
}
}
]
}
}
EOM
# POST 'conveyed-information-responses' to running
curl -i -X POST --data @conveyed-information-responses.json -H "Content-Type:application/yang-data+json" --\
cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/restconf/ds/ietf-da\
tastores:running 1> output/post_conveyed_information_responses2.out 2>/dev/null
rm -f conveyed-information-responses.json
Output:
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:10 GMT
Server: <redacted>
Configure the ‘response-manager’ node inside the device object to return “my-onboarding-information”. A “catch-all” rule tells STZPD to return the just configured ‘my-onboarding-information’.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize body for the POST request
cat << EOM > response-manager.json
{
"wn-sztpd-1:response-manager": {
"matched-response": [
{
"name": "catch-all-response",
"response": {
"conveyed-information": {
"onboarding-information": {
"reference": "my-onboarding-information"
}
}
}
}
]
}
}
EOM
# POST 'response-manager' to *device*
curl -i -X POST --data @response-manager.json -H "Content-Type:application/yang-data+json" --cacert nbi_tru\
st_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/restconf/ds/ietf-datastores:runni\
ng/wn-sztpd-1:devices/device=my-serial-number 1> output/post_response_manager2.out 2>/dev/null
# cleanup
rm -f response-manager.json
Output:
HTTP/1.1 201 Created
Content-Length: 0
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:10 GMT
Server: <redacted>
Request: (Same as in the Simulate Device Trying to Get Bootstrapping Data section)
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.json
{
"ietf-sztp-bootstrap-server:input" : {
"hw-model" : "model-x",
"os-name" : "vendor-os",
"os-version" : "17.3R2.1",
"nonce" : "BASE64VALUE="
}
}
EOM
# POST 'input' for the "get-bootstrapping-data" RPC resource
curl -i -X POST --data @input.json -H "Content-Type:application/yang-data+json" --cacert sbi_trust_chain.pe\
m --key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-num\
ber:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data \
1> output/post_rpc_input.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_rpc_input.out
# cleanup
rm -f input.json
Output:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 1187
Date: Fri, 15 Jan 2021 02:38:10 GMT
Server: <redacted>
{
"ietf-sztp-bootstrap-server:output": {
"conveyed-information": "MIIDOQYLKoZIhvcNAQkQASugggMoBIIDJHsKICAiaWV0Zi1zenRwLWNvbnZleWVkLWluZm86b25ib2\
FyZGluZy1pbmZvcm1hdGlvbiI6IHsKICAgICJib290LWltYWdlIjogewogICAgICAiZG93bmxvYWQtdXJpIjogWwogICAgICAgICJodHRwc\
zovL2V4YW1wbGUuY29tL215LWJvb3QtaW1hZ2UuaW1nIgogICAgICBdLAogICAgICAiaW1hZ2UtdmVyaWZpY2F0aW9uIjogWwogICAgICAg\
IHsKICAgICAgICAgICJoYXNoLWFsZ29yaXRobSI6ICJpZXRmLXN6dHAtY29udmV5ZWQtaW5mbzpzaGEtMjU2IiwKICAgICAgICAgICJoYXN\
oLXZhbHVlIjogIjZmOjg3OjBiOmFmOjNjOjNhOmZlOjAzOjE0OjU3OjI0OjI3OmM2OmJhOjQ5OjA0OmI5OjUyOjk0OjQzOjhkOmI4OjdiOj\
IxOmIzOmE5OjI0OjkyOjMxOjJjOjAwOmQ5IgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJwcmUtY29uZmlndXJhdGlvbi1zY3Jpc\
HQiOiAiSXk5aWFXNHZZbUZ6YUFwbFkyaHZJQ0pwYm5OcFpHVWdkR2hsSUhCeVpTMWpiMjVtYVdkMWNtRjBhVzl1TFhOamNtbHdkQzR1TGlJ\
SyIsCiAgICAiY29uZmlndXJhdGlvbi1oYW5kbGluZyI6ICJtZXJnZSIsCiAgICAiY29uZmlndXJhdGlvbiI6ICJQSFJ2Y0NCNGJXeHVjejB\
pYUhSMGNITTZMMlY0WVcxd2JHVXVZMjl0TDJOdmJtWnBaeUkrQ2lBZ1BHRnVlUzE0Yld3dFkyOXVkR1Z1ZEMxdmEyRjVMejRLUEM5MGIzQS\
tDZz09IiwKICAgICJwb3N0LWNvbmZpZ3VyYXRpb24tc2NyaXB0IjogIkl5OWlhVzR2WW1GemFBcGxZMmh2SUNKcGJuTnBaR1VnZEdobElIQ\
nZjM1F0WTI5dVptbG5kWEpoZEdsdmJpMXpZM0pwY0hRdUxpNGlDZz09IgogIH0KfQ=="
}
}
In addition to RFC 8572 enabling a device to obtain bootstrapping data, it also enables a device to post progress reports that enable a controller / NMS application to:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > bootstrap-complete.json
{
"ietf-sztp-bootstrap-server:input" : {
"progress-type" : "bootstrap-complete",
"message" : "Dynamically generated SSH host key included.",
"ssh-host-keys" : {
"ssh-host-key" : [
{
"algorithm" : "ssh-rsa",
"key-data" : "BASE64VALUE="
}
]
}
}
}
EOM
# POST it to the "report-progress" RPC resource
curl -i -X POST --data @bootstrap-complete.json -H "Content-Type:application/yang-data+json" --cacert sbi_t\
rust_chain.pem --key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user \
my-serial-number:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:report-pro\
gress 1> output/post_progress_report.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_progress_report.out
# cleanup
rm -f bootstrap-complete.json
Output:
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:11 GMT
Server: <redacted>
Now delete all of the onboarding config to get back to baseline (not that it matters).
Note that the configuration is removed in the opposite order to avoid SZTPD throwing a validation error due to dangling references.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# These are removed in opposite order to avoid dangling reference validation errors.
curl -i -X DELETE --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080\
/restconf/ds/ietf-datastores:running/wn-sztpd-1:devices/device=my-serial-number/response-manager 1> output/\
delete_onboarding_info.out 2>/dev/null
curl -i -X DELETE --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080\
/restconf/ds/ietf-datastores:running/wn-sztpd-1:conveyed-information-responses 1>> output/delete_onboarding\
_info.out 2>/dev/null
curl -i -X DELETE --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080\
/restconf/ds/ietf-datastores:running/wn-sztpd-1:boot-images 1>> output/delete_onboarding_info.out 2>/dev/nu\
ll
curl -i -X DELETE --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080\
/restconf/ds/ietf-datastores:running/wn-sztpd-1:scripts 1>> output/delete_onboarding_info.out 2>/dev/null
curl -i -X DELETE --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080\
/restconf/ds/ietf-datastores:running/wn-sztpd-1:configurations 1>> output/delete_onboarding_info.out 2>/dev\
/null
Output:
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:11 GMT
Server: <redacted>
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:11 GMT
Server: <redacted>
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:11 GMT
Server: <redacted>
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:11 GMT
Server: <redacted>
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:11 GMT
Server: <redacted>
Notice how all the commands run above appear below.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
curl -i -X GET --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/re\
stconf/ds/ietf-datastores:operational/wn-sztpd-1:audit-log 1> output/get_audit_log.out 2>/dev/null
Output:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 7719
Date: Fri, 15 Jan 2021 02:38:12 GMT
Server: <redacted>
{
"wn-sztpd-1:audit-log": {
"log-entry": [
{
"comment": "No authorization required for fresh installs.",
"timestamp": "2021-01-15T02:38:00Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running",
"outcome": "success",
"method": "PUT"
},
{
"comment": "Client cert required but none passed for serial number my-serial-number",
"timestamp": "2021-01-15T02:38:07Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:9090",
"path": "/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library",
"outcome": "failure",
"method": "HEAD"
},
{
"timestamp": "2021-01-15T02:38:07Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:9090",
"path": "/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library",
"outcome": "success",
"method": "HEAD"
},
{
"timestamp": "2021-01-15T02:38:07Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:9090",
"path": "/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:07Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:08Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:08Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:devices/device=my-serial-number",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:08Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:9090",
"path": "/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:09Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:devices/device=my-serial-number/response-m\
anager",
"outcome": "success",
"method": "DELETE"
},
{
"timestamp": "2021-01-15T02:38:09Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:conveyed-information-responses",
"outcome": "success",
"method": "DELETE"
},
{
"timestamp": "2021-01-15T02:38:09Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:bootstrap-servers",
"outcome": "success",
"method": "DELETE"
},
{
"timestamp": "2021-01-15T02:38:09Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:10Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:10Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:10Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:10Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:devices/device=my-serial-number",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:10Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:9090",
"path": "/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data",
"outcome": "success",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:11Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:devices/device=my-serial-number/response-m\
anager",
"outcome": "success",
"method": "DELETE"
},
{
"timestamp": "2021-01-15T02:38:11Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:conveyed-information-responses",
"outcome": "success",
"method": "DELETE"
},
{
"timestamp": "2021-01-15T02:38:11Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:boot-images",
"outcome": "success",
"method": "DELETE"
},
{
"timestamp": "2021-01-15T02:38:11Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:scripts",
"outcome": "success",
"method": "DELETE"
},
{
"timestamp": "2021-01-15T02:38:11Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:8080",
"path": "/restconf/ds/ietf-datastores:running/wn-sztpd-1:configurations",
"outcome": "success",
"method": "DELETE"
},
{
"timestamp": "2021-01-15T02:38:11Z",
"source-ip": "127.0.0.1",
"host": "127.0.0.1:9090",
"path": "/restconf/operations/ietf-sztp-bootstrap-server:report-progress",
"outcome": "success",
"method": "POST"
}
]
}
}
Notice how the “GET” on yang-library resource, and all of the get-bootstrapping-data
RPC requests, and the report-progress
RPC request, from above all appear below.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
curl -i -X GET --cacert nbi_trust_chain.pem --user my-admin@example.com:my-secret https://127.0.0.1:8080/re\
stconf/ds/ietf-datastores:operational/wn-sztpd-1:devices/device=my-serial-number/bootstrapping-log 1> outpu\
t/get_bootstrapping_log.out 2>/dev/null
Output:
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 9682
Date: Fri, 15 Jan 2021 02:38:13 GMT
Server: <redacted>
{
"wn-sztpd-1:bootstrapping-log": {
"log-entry": [
{
"timestamp": "2021-01-15T02:38:07Z",
"source-ip": "127.0.0.1",
"return-code": 200,
"method": "HEAD",
"path": "/restconf/ds/ietf-datastores:operational/ietf-yang-library:yang-library"
},
{
"error-returned": {
"ietf-restconf:errors": {
"error": [
{
"error-type": "application",
"error-tag": "data-missing",
"error-message": "No responses configured."
}
]
}
},
"timestamp": "2021-01-15T02:38:07Z",
"source-ip": "127.0.0.1",
"event-details": {
"get-bootstrapping-data-event": {
"selected-response": "no-responses-configured",
"passed-input": {
"input": [
{
"value": "model-x",
"key": "hw-model"
},
{
"value": "vendor-os",
"key": "os-name"
},
{
"value": "17.3R2.1",
"key": "os-version"
},
{
"value": "extralongbase64encodedvaluc=",
"key": "nonce"
}
]
}
}
},
"return-code": 404,
"path": "/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:09Z",
"source-ip": "127.0.0.1",
"event-details": {
"get-bootstrapping-data-event": {
"selected-response": "catch-all-response",
"passed-input": {
"input": [
{
"value": "model-x",
"key": "hw-model"
},
{
"value": "vendor-os",
"key": "os-name"
},
{
"value": "17.3R2.1",
"key": "os-version"
},
{
"value": "extralongbase64encodedvaluc=",
"key": "nonce"
}
]
},
"response-details": {
"managed-response": {
"conveyed-information": {
"redirect-information": {
"referenced-definition": "my-redirect-information"
}
}
}
}
}
},
"return-code": 200,
"path": "/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:10Z",
"source-ip": "127.0.0.1",
"event-details": {
"get-bootstrapping-data-event": {
"selected-response": "catch-all-response",
"passed-input": {
"input": [
{
"value": "model-x",
"key": "hw-model"
},
{
"value": "vendor-os",
"key": "os-name"
},
{
"value": "17.3R2.1",
"key": "os-version"
},
{
"value": "extralongbase64encodedvaluc=",
"key": "nonce"
}
]
},
"response-details": {
"managed-response": {
"conveyed-information": {
"onboarding-information": {
"referenced-definition": "my-onboarding-information"
}
}
}
}
}
},
"return-code": 200,
"path": "/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data",
"method": "POST"
},
{
"timestamp": "2021-01-15T02:38:11Z",
"source-ip": "127.0.0.1",
"event-details": {
"report-progress-event": {
"passed-input": {
"ssh-host-keys": {
"ssh-host-key": [
{
"key-data": "base64encodedvalue==",
"algorithm": "ssh-rsa"
}
]
},
"message": "Dynamically generated SSH host key included.",
"progress-type": "bootstrap-complete"
},
"dynamic-callout": {
"no-callout-configured": [
null
]
}
}
},
"return-code": 204,
"path": "/restconf/operations/ietf-sztp-bootstrap-server:report-progress",
"method": "POST"
}
]
}
}
This section goes over standards-based behavior that may not be immediately obvious to some readers.
SZTPD attempts to not require HTTP headers (e.g., “Accept”, “Content-Type”, etc.), but it strictly enforces that the correct headers are present when needed.
When an “Accept” header is not passed, an implied value will be derived from the “Content-Type” header, if it is present. Errors are returned using the implied value, or “text/plain” otherwise.
SZTPD does not have a default encoding, and so wildcard “Accept” header values, such as “/” or similar, are not supported. When the request demands a response (e.g., GET), an “Accept” header must be provided.
SZTPD is not able to auto-detect the encoding of request bodies, and thus a “Content-Type” header must be provided when a request body is included in a request.
An ordered list is one in which the order matters. In YANG, the ‘ordered-by user’ statement is used to indicate when the order matters for a ‘list’ or ‘leaf-list’. Please see Section 7.7.1 in the YANG specification for details.
There are three ordered lists in SZTPD, one ‘list’ and two ‘leaf-lists’ as follows:
The ordering of a user-ordered list is initiailly specified when the list is created, assuming more than one entry to defined at that time, and maintained thereafter whenever a new entry is added to the list (e.g., using the POST method) and/or replaced (i.e., using the PUT method) using the ‘insert’ and ‘point’ query parameters, as described in the RESTCONF specification by Section 4.8.5 and Section 4.8.6 respectively.
Assuming a device’s “response-manager” contains the ordered list of “matched-response” entries: “resp1”, “resp2”, and “resp3”, then the command:
$ cat matched-response.json
{
"wn-sztpd-1:matched-response": [
{
'name': 'new',
'response': {
'none': [None]
}
}
]
}
$ curl -i -X POST --data @matched-response.json -H "Content-Type:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:running/wn-sztpd-1:devices/device=my-serial\
-number/response-manager?insert=after&point=/wn-sztpd-1:devices/device=my-serial-number/respo\
nse-manager/matched-response=resp1
would result in the list of entries: “resp1”, “new”, “resp2”, and “resp3”.
Assuming a redirect-information-response contains the ordered list of “bootstrap-server” entries: “bs1”, “bs2”, and “bs3”, then the command:
$ cat bootstrap-server.json
{
"wn-sztpd-1:bootstrap-server": [
"bs-3"
]
}
$ curl -i -X PUT --data @bootstrap-server.json -H "Content-Type:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:running/wn-sztpd-1:conveyed-information-re\
sponses/redirect-information-response=my-redirect-information/redirect-information/bootstrap\
-server=bs3?insert=before&point=/wn-sztpd-1:conveyed-information-responses/redirect-informat\
ion-response=my-redirect-information/redirect-information/bootstrap-server=bs2
would result in the list of entries: “bs1”, “bs3”, and “bs2”.
Special characters are herein defined as those that must be escaped in order to be passed into or out of the server.
According to Section 3.5.3 of RFC 8040, any reserved characters in a resource identifier (i.e., key values) MUST be percent-encoded.
This applies to any URL that encodes a ‘list’ or ‘leaf-list’ instance, the the ‘key’ value contains reserved characters, they must be escaped when placed into the URL.
That said, a worst-case scenario arises when trying the insert or move an entry into the “boot-images/boot-image/download-uri” ordered list (see Ordered Lists) as, in this case, a URL must be encoded into a URL.
Assuming the configured “download-uri” leaf-list contains values as follows:
{
"wn-sztpd-1:download-uri" : [
https://cdn1.example.com/path/to/image/file,
https://cdn2.example.com/path/to/image/file,
https://cdn3.example.com/path/to/image/file
]
}
then the command:
$ cat download-uri.json
{
"wn-sztpd-1:download-uri": [
https://new4.example.com/path/to/image/file
]
}
$ curl -i -X POST --data @download-uri.json -H "Content-Type:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:running/wn-sztpd-1:boot-images/boot-ima\
ge=vendoros-19.2r1b6.img?insert=after&point=/wn-sztpd-1:boot-images/boot-image=vendoros-1\
9.2r1b6.img/download-uri=https%3A%2F%2Fcdn1.example.com%2Fpath%2Fto%2Fimage%2Ffile
would result in the list of entries:
{
"wn-sztpd-1:download-uri" : [
https://cdn1.example.com/path/to/image/file,
https://new4.example.com/path/to/image/file,
https://cdn2.example.com/path/to/image/file,
https://cdn3.example.com/path/to/image/file
]
}
Assuming the configured “download-uri” leaf-list contains values as follows:
{
"wn-sztpd-1:download-uri" : [
https://cdn1.example.com/path/to/image/file,
https://new4.example.com/path/to/image/file,
https://cdn2.example.com/path/to/image/file,
https://cdn3.example.com/path/to/image/file
]
}
then the command:
$ cat download-uri.json
{
"wn-sztpd-1:download-uri": [
https://new4.example.com/path/to/image/file
]
}
$ curl -i -X POST --data @download-uri.json -H "Content-Type:application/yang-data+json" \
http://127.0.0.1:8080/restconf/ds/ietf-datastores:running/wn-sztpd-1:boot-images/boot-ima\
ge=vendoros-19.2r1b6.img/download-uri=https%3A%2F%2Fnew4.example.com%2Fpath%2Fto%2Fimage%\
2Ffile?insert=before&point=/wn-sztpd-1:boot-images/boot-image=vendoros-19.2r1b6.img/downl\
oad-uri=https%3A%2F%2Fcdn3.example.com%2Fpath%2Fto%2Fimage%2Ffile
would result in the list of entries:
{
"wn-sztpd-1:download-uri" : [
https://cdn1.example.com/path/to/image/file,
https://cdn2.example.com/path/to/image/file,
https://new4.example.com/path/to/image/file,
https://cdn3.example.com/path/to/image/file
]
}
Some lists, especially lists representing time-series data (i.e., logs), can grow to be large in size. Client applications wishing to browse thru the list entries may only wish to do so in chunks or pages.
There is an effort, spearheaded by Watsen Networks, to defined a standard for list pagination. While it is too early to post even a link to the budding standard, SZTPD has initial support for three new query parameters:
+-----------+---------+-----------------------------------------+
| Name | Methods | Description |
+-----------+---------+-----------------------------------------+
| limit | GET, | Limits the number of entries returned. |
| | HEAD | If not specified, the number of entries |
| | | that may be returned in unbounded. |
| | | |
| offset | GET, | Indicates the number of entries in the |
| | HEAD | result set that should the skipped over |
| | | when preparing the response. If not |
| | | specified, then no entries in the |
| | | result set are skipped. |
| | | |
| direction | GET, | Indicates the direction that the result |
| | HEAD | set is to be traversed. If not |
| | | specified, then the result set is |
| | | traversed in the "forward" direction. |
+-----------+---------+-----------------------------------------+
SZTPD reacts to some triggers automatically.
SZTPD reacts to some configurations changes. Simple examples include:
Configuration-based triggers are discussed further in Tracking.
SZTPD may set clock triggers. For instance, to note when an object should be purged.
Much of SZTPD’s reactive functionality depends on triggers.
SZTPD will be able to track where referenced objects are used so as to detect when the objects are no longer referenced. Timestamps track when the object was created, last modified, first referenced, and last referenced.
Known when an object was last referenced enables SZTPD to determine when the object will be subject to expiration, unless updated or referenced in the interim.
When implemented, SZTPD sends notifications with expedited urgency when an object is getting close to expiration.
Devices are special objects in that nothing references them and yet it is desired to purge them when approporiate and, furthermore, to track if/when a device performed bootstrapping events.
SZTPD uses plugins to enable custom logic for Dynamic Callouts.
Configuring SZTPD to use a plugin is a two-step process:
python -c 'import pkg_resources; print(pkg_resources.resource_filename("sztpd", "plugins/"))'
Assuming a plugin a installed as follows:
PLUGIN_DIR=`python -c 'import pkg_resources; print(pkg_resources.resource_filename("sztpd", "plugins"))'`
echo $PLUGIN_DIR
cat << EOM > $PLUGIN_DIR/my-plugin.py
import sys
def relay_progress_report_function(input, opaque):
print("INSIDE relay_progress_report_function()...")
print("input = " + str(input))
print("opaque = " + str(opaque))
print("sys.version = " + sys.version)
EOM
And that the configuration contains the following, in addition to other configurations:
"wn-sztpd-x:preferences": {
"system": {
"plugins": {
"plugin": [
{
"name": "my-plugin",
"functions": {
"function": [
{
"name": "relay_progress_report_function"
}
]
}
}
]
}
},
"outbound-interactions": {
"relay-progress-report-callout": "my-relay-progress-report-callout"
}
},
"wn-sztpd-x:dynamic-callouts": {
"dynamic-callout": [
{
"name": "my-relay-progress-report-callout",
"rpc-supported": "wn-sztpd-rpcs:relay-progress-report",
"callback": {
"plugin": "my-plugin",
"function": "relay_progress_report_function"
},
"opaque": {
"empty": [None],
"boolean": True,
"string": "foobar",
"list": [ 1, 2, 3 ],
"dict": {
"a": 1,
"b": 2
}
}
}
]
}
Then, when a device sends a progress report, the following may appear in the console where SZTPD is running4:
============================= Note: '\' line wrapping per RFC 8792] =================================
INSIDE relay_progress_report_function()...
input = {'serial-number': 'my-serial-number', 'source-ip-address': '127.0.0.1', 'from-device': {'iet\
f-sztp-bootstrap-server:input': {'progress-type': 'bootstrap-complete', 'message': 'message sent via\
XML', 'ssh-host-keys': {'ssh-host-key': [{'algorithm': 'ssh-rsa', 'key-data': 'BASE64VALUE='}, {'al\
gorithm': 'rsa-sha2-256', 'key-data': 'BASE64VALUE='}]}, 'trust-anchor-certs': {'trust-anchor-cert':\
['BASE64VALUE=']}}}}
opaque = {'empty': [None], 'boolean': True, 'string': 'foobar', 'list': [1, 2, 3], 'dict': {'a': 1, \
'b': 2}}
sys.version = 3.8.2 (default, Nov 11 2020, 16:34:19)
[Clang 12.0.0 (clang-1200.0.32.21)]
This section provides a high-level overview of the API using YANG tree diagrams.
Tree diagrams enable the general structure of the data to be understood but, for full understanding, it is necessary to look at the YANG modules themselves.
The YANG modules used by SZTPD can be found in the “yang” directory in the sztpd
installation directory (e.g., site-packages/sztpd/yang/*.yang). Each Python installation has its own location for where it installs Python modules. This may vary by the version of Python installed and if virtual environments are used. The following command can be used to find the directory the YANG files are located in:
python -c 'import pkg_resources; print(pkg_resources.resource_filename("sztpd", "yang/"))'
DISCLAIMER: the YANG models are unsually complex, due to the modules needing to present different product modes.
The following sections are presented in sorted order.
The following tree diagram illustrates the NBI used for configuring “admin-accounts”.
+--rw admin-accounts
+--rw admin-account* [email-address]
+--rw email-address string
+--rw fullname? string
+--rw password iana-crypt-hash:crypt-hash
+--ro password-last-modified ietf-yang-types:date-and-time
+--rw access enumeration
+---x resend-activation-email
Each account is keyed by an email address. Use of an email address enables mapping to subtenant mapping (for deployments running in product mode ‘x’, as email addresses are globally unique, and otherwise enables the email-based administrator account verification mechanism provided by SZTPD.
The following tree diagram illustrates the NBI used viewing audit logs (“ro” stands for “read-only”).
+--ro audit-log
+--ro log-entry*
+--ro timestamp ietf-yang-types:date-and-time
+--ro source-ip ietf-inet-types:ip-address
+--ro source-proxies* string
+--ro host string
+--ro method enumeration
+--ro path string
+--ro outcome enumeration
+--ro comment? string
The following tree diagram illustrates the NBI used for configuring boot-image
records.
+--rw boot-images {wn-sztpd-0:onboarding-supported}?
+--rw boot-image* [name]
+--rw name string
+--rw os-name? string
+--rw os-version? string
+--rw download-uri* ietf-inet-types:uri
+--rw image-verification* [hash-algorithm]
| +--rw hash-algorithm identityref
| +--rw hash-value ietf-yang-types:hex-string
+--ro reference-statistics
+--ro reference-count uint32
+--ro last-referenced union
The boot-image
records are used in constructing RFC 8572 based “onboarding information” responses.
The following tree diagram illustrates the NBI used for configuring “bootstrap-server” records.
+--rw bootstrap-servers
+--rw bootstrap-server* [name]
+--rw name string
+--rw address ietf-inet-types:host
+--rw port? ietf-inet-types:port-number <443>
+--rw trust-anchor? ietf-crypto-types:trust-anchor-cert-cms
+--ro reference-statistics
+--ro reference-count uint32
+--ro last-referenced union
The bootstrap-server
records are used in constructing RFC 8572 based “redirect information” responses.
The following tree diagram illustrates the NBI used for configuring configuration
records.
+--rw configurations {wn-sztpd-0:onboarding-supported}?
+--rw configuration* [name]
+--rw name string
+--rw configuration-handling? enumeration
+--rw config? binary
+--ro reference-statistics
+--ro reference-count uint32
+--ro last-referenced union
The configuration
records are used in constructing RFC 8572 based “onboarding information” responses.
The following tree diagram illustrates the NBI used for configuring conveyed-information-responses
records.
+--rw conveyed-information-responses
+--rw redirect-information-response* [name]
| +--rw name string
| +--rw redirect-information
| | +--rw bootstrap-server* -> ../../../../bootstrap-servers/bootstrap-server/name
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw onboarding-information-response* [name] {wn-sztpd-0:onboarding-supported}?
+--rw name string
+--rw onboarding-information
| +--rw boot-image -> ../../../../boot-images/boot-image/name
| +--rw pre-configuration-script? -> ../../../../scripts/pre-configuration-script/name
| +--rw configuration? -> ../../../../configurations/configuration/name
| +--rw post-configuration-script? -> ../../../../scripts/post-configuration-script/name
+--ro reference-statistics
+--ro reference-count uint32
+--ro last-referenced union
The conveyed-information-responses
records are used in constructing RFC 8572 based “redirect” and “onboarding” information responses.
The “/device-types” tree enables configuration of device types to be recognized by the system.
Not only is being able to associate a device with a type helpful on its own, but each “device-type” entry enables more than just that, as explained below.
Each device-type can optionally indicate if devices of that type authenticate themselves with an identity certificate (e.g., an IDevID) and, if so, further indicate the trust-anchor certificate in the Truststore that can authenticate the device’s idenitity certificate. This enables application specific verification that the device’s client certificate (i.e., its IDevID) exactly matches the expected certificate chain.
Each device-type can also optionally specify a callout SZTPD should call in order to determine if the specific tenant is the rightful owner of the devices of that device type. The callout is specified per device-type as backend logic may vary by device-type.
Important: In the “tenant” view, this entire data-tree is read-only. That is, all the “rw” would be shown as “ro” if this were the tenant view’s tree diagram. The /device-types tree is read-only in the “tenant” view because device types can only be set at the system level via the ‘native’ view.
The following tree diagram illustrates the NBI used for configuring device
records.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
+--rw device-types
+--rw device-type* [name]
+--rw name string
+--rw identity-certificates!
| +--rw verification
| | +--rw local-truststore-reference {ietf-truststore:certificates}?
| | +--rw certificate-bag -> /truststore/certificate-bags/certificate-bag/name
| | +--rw certificate -> /truststore/certificate-bags/certificate-bag[name = current()/\
../certificate-bag]/certificate/name
| +--rw serial-number-extraction? identityref <wn-x509-c2n:serial-number>
+--rw ownership-authorization!
| +--rw dynamic-callout
| +--rw reference? -> /dynamic-callouts/dynamic-callout/name
+--rw voucher-aquisition!
+--rw dynamic-callout
+--rw reference? -> /dynamic-callouts/dynamic-callout/name
The following tree diagram illustrates the NBI used for configuring device
records.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
+--rw devices
+--rw device* [serial-number]
+--rw serial-number string
+--rw activation-code? iana-crypt-hash:crypt-hash
+--rw response-manager
| +--rw matched-response* [name]
| +--rw name string
| +--rw match-criteria!
| | +--rw match* [key]
| | +--rw key string
| | +--rw not? empty
| | +--rw (test-type)
| | +--:(present)
| | | +--rw present? empty
| | +--:(value)
| | | +--rw value? string
| | +--:(regex)
| | +--rw regex? string
| +--rw response
| +--rw reporting-level? enumeration <minimal> {wn-sztpd-0:onboarding-supported}?
| +--rw (response-handler)
| +--:(none)
| | +--rw none? empty
| +--:(managed-response)
| +--rw conveyed-information
| +--rw (conveyed-information-handler)
| +--:(use-dynamic-callout)
| | +--rw dynamic-callout
| | +--rw reference? -> ../../../../../../../../dynamic-callouts/dynamic-c\
allout/name
| +--:(redirect-information)
| | +--rw redirect-information
| | +--rw (local-or-reference)
| | +--:(reference)
| | +--rw reference? -> ../../../../../../../../conveyed-information\
-responses/redirect-information-response/name
| +--:(onboarding-information) {wn-sztpd-0:onboarding-supported}?
| +--rw onboarding-information
| +--rw (local-or-reference)
| +--:(reference)
| +--rw reference? -> ../../../../../../../../conveyed-information\
-responses/onboarding-information-response/name
+--ro bootstrapping-log
| +--ro log-entry*
| +--ro timestamp ietf-yang-types:date-and-time
| +--ro source-ip ietf-inet-types:ip-address
| +--ro method string
| +--ro path string
| +--ro return-code uint16
| +--ro error-returned? anydata
| +--ro event-details
| +--ro (event-type)
| +--:(get-bootstrapping-data-event)
| | +--ro get-bootstrapping-data-event
| | +--ro passed-input anydata
| | +--ro selected-response? union
| | +--ro response-details
| | +--ro (response-type)
| | +--:(managed-response)
| | +--ro managed-response
| | +--ro conveyed-information
| | +--ro (conveyed-information-handler)
| | +--:(dynamic-callout)
| | | +--ro dynamic-callout
| | | +--ro (result-type)?
| | | +--:(no-callout-configured)
| | | | +--ro no-callout-configured? empty
| | | +--:(callout-configured)
| | | +--ro name string
| | | +--ro rpc-supported identityref
| | | +--ro callout-type enumeration
| | | +--ro (callback-or-webhook)?
| | | +--:(callback)
| | | +--ro callback-details
| | | | +--ro plugin string
| | | | +--ro function string
| | | +--ro callback-results
| | | +--ro (exit-status)
| | | +--:(exception-thrown)
| | | | +--ro exception-thrown? string
| | | +--:(exited-normally)
| | | +--ro exited-normally? string
| | +--:(redirect-information)
| | | +--ro redirect-information
| | | +--ro (local-or-reference)
| | | +--:(reference)
| | | +--ro referenced-definition? string
| | +--:(onboarding-information) {wn-sztpd-0:onboarding-supported}?
| | +--ro onboarding-information
| | +--ro (local-or-reference)
| | +--:(reference)
| | +--ro referenced-definition? string
| +--:(report-progress-event) {wn-sztpd-0:onboarding-supported}?
| +--ro report-progress-event
| +--ro passed-input anydata
| +--ro dynamic-callout
| +--ro (result-type)?
| +--:(no-callout-configured)
| | +--ro no-callout-configured? empty
| +--:(callout-configured)
| +--ro name string
| +--ro rpc-supported identityref
| +--ro callout-type enumeration
| +--ro (callback-or-webhook)?
| +--:(callback)
| +--ro callback-details
| | +--ro plugin string
| | +--ro function string
| +--ro callback-results
| +--ro (exit-status)
| +--:(exception-thrown)
| | +--ro exception-thrown? string
| +--:(exited-normally)
| +--ro exited-normally? string
+--ro lifecycle-statistics
| +--ro nbi-access-stats
| | +--ro created ietf-yang-types:date-and-time
| | +--ro num-times-modified uint16
| | +--ro last-modified ietf-yang-types:date-and-time
| +--ro sbi-access-stats
| +--ro num-times-accessed uint16
| +--ro first-accessed ietf-yang-types:date-and-time
| +--ro last-accessed ietf-yang-types:date-and-time
+--rw device-type -> /device-types/device-type/name
Device records are keyed by serial number, enabling device to tenant mapping, as serial numbers are globally unique.
Each device record includes the device’s lifecycle statistics (key north and south bound interactions) and bootstrapping log (a history of device-initiated interactions)
The device
records are used in constructing RFC 8572 based “redirect” and “onboarding” information responses.
The following tree diagram illustrates the NBI used for configuring dynamic callouts that, at this time, must be implemented by a plugin-based callback but, in a future release, may be implemented as via a webhook.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
+--rw dynamic-callouts
+--rw dynamic-callout* [name]
+--rw name string
+--rw rpc-supported identityref
+--rw (callout-type)
+--:(use-callback)
+--rw callback
| +--rw plugin -> /preferences/system/plugins/plugin/name
| +--rw function -> /preferences/system/plugins/plugin[name = current()/../plugin]/functi\
ons/function/name
+--rw opaque? anydata
The following tree diagram illustrates the NBI used for configuring keys held in the keystore
.
+--rw keystore
+--rw asymmetric-keys
| +--rw asymmetric-key* [name]
| +--rw name string
| +--rw public-key-format identityref
| +--rw public-key binary
| +--rw private-key-format? identityref
| +--rw (private-key-type)
| | +--:(cleartext-private-key)
| | | +--rw cleartext-private-key? binary
| | +--:(hidden-private-key)
| | +--rw hidden-private-key? empty
| +--rw certificates
| | +--rw certificate* [name]
| | +--rw name string
| | +--rw cert-data ietf-crypto-types:end-entity-cert-cms
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw symmetric-keys
+--rw symmetric-key* [name]
+--rw name string
+--rw key-format? identityref
+--rw (key-type)
+--:(cleartext-key)
| +--rw cleartext-key? binary
+--:(hidden-key)
+--rw hidden-key? empty
The keys held in the keystore are used in the transport
configuration, e.g., to hold SZTPD’s private key used for each listening port (see the Listening Ports and the APIs They Present in the Installation Guide).
The following tree diagram illustrates the NBI used for configuring system and tenant-level preferences.
+--rw preferences
+--rw admin-accounts
| +--rw new-account-verification
| | +--rw subject? string
| | +--rw cc? string
| | +--rw body? string
| +--rw passwords
| +--rw strength-testing!
| +--rw min-length? uint16 <16>
+--rw outbound-interactions
| +--rw relay-notification-callout? -> ../../../dynamic-callouts/dynamic-callout/name
| +--rw relay-progress-report-callout? -> ../../../dynamic-callouts/dynamic-callout/name
+--rw system
+--rw hostname? ietf-inet-types:host
+--rw email-from-address? string <SZTPD Administrator <root@$SZTP-SERVER-ADDRESS>>
+--rw features
| +--rw onboarding-supported? boolean <true> {wn-sztpd-0:onboarding-supported}?
+--rw plugins
+--rw plugin* [name]
+--rw name string
+--rw functions
+--rw function* [name]
+--rw name string
The following tree diagram illustrates the NBI used for configuring script
records.
+--rw scripts {wn-sztpd-0:onboarding-supported}?
+--rw pre-configuration-script* [name]
| +--rw name string
| +--rw script? ietf-sztp-conveyed-info:script
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw post-configuration-script* [name]
+--rw name string
+--rw script? ietf-sztp-conveyed-info:script
+--ro reference-statistics
+--ro reference-count uint32
+--ro last-referenced union
The script
records are used in constructing RFC 8572 based “onboarding information” responses.
For deployments using product mode ‘x’, the following tree diagram illustrates a snippet of the NBI used for configuring tenants.
+--rw tenants
+--rw tenant* [name]
Unlike all the other Northbound Interface sections, this section illustrates only the place in the hierarchy where the tenant containers are defined. Not shown are that each tenant
container contains an instance of every other Northbound Interface section in it as well (with exception to the transport
, which can only be configured by the host system.
The following tree diagram illustrates the NBI used for configuring transport
records.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
+--rw transport
+--rw listen! {ietf-restconf-server:http-listen or ietf-restconf-server:https-listen}?
+--rw endpoint* [name]
+--rw name string
+--rw (transport)
| +--:(http) {ietf-restconf-server:http-listen}?
| | +--rw http
| | +--rw external-endpoint!
| | | +--rw address ietf-inet-types:ip-address
| | | +--rw port? ietf-inet-types:port-number <443>
| | +--rw tcp-server-parameters
| | | +--rw local-address ietf-inet-types:ip-address
| | | +--rw local-port? ietf-inet-types:port-number <80>
| | +--rw http-server-parameters
| | | +--rw server-name? string
| | +--rw restconf-server-parameters
| | +--rw client-identity-mappings
| | +--rw cert-to-name* [id]
| | +--rw id uint32
| | +--rw fingerprint? ietf-x509-cert-to-name:tls-fingerprint
| | +--rw map-type identityref
| | +--rw name string
| +--:(https) {ietf-restconf-server:https-listen}?
| +--rw https
| +--rw tcp-server-parameters
| | +--rw local-address ietf-inet-types:ip-address
| | +--rw local-port? ietf-inet-types:port-number <443>
| +--rw tls-server-parameters
| | +--rw server-identity
| | | +--rw (auth-type)
| | | +--:(certificate) {ietf-tls-server:x509-certificate-auth}?
| | | +--rw certificate
| | | +--rw (local-or-keystore)
| | | +--:(local-keystore)
| | | +--rw reference
| | | +--rw asymmetric-key? -> /keystore/asymmetric-keys/asymmetric\
-key/name
| | | +--rw certificate? -> /keystore/asymmetric-keys/asymmetric\
-key[name = current()/../asymmetric-key]/certificates/certificate/name
| | +--rw client-authentication! {ietf-tls-server:client-auth-config-supported}?
| | +--rw ca-certs! {ietf-tls-server:x509-certificate-auth}?
| | | +--rw (local-or-truststore)
| | | +--:(local-truststore) {ietf-truststore:certificates,ietf-tls-server:client\
-auth-config-supported}?
| | | +--rw local-truststore-reference? -> /truststore/certificate-bags/cert\
ificate-bag/name
| | +--rw ee-certs! {ietf-tls-server:x509-certificate-auth}?
| | +--rw (local-or-truststore)
| | +--:(local-truststore) {ietf-truststore:certificates,ietf-tls-server:client\
-auth-config-supported}?
| | +--rw local-truststore-reference? -> /truststore/certificate-bags/cert\
ificate-bag/name
| +--rw http-server-parameters
| | +--rw server-name? string
| +--rw restconf-server-parameters
| +--rw client-identity-mappings
| +--rw cert-to-name* [id]
| +--rw id uint32
| +--rw fingerprint? ietf-x509-cert-to-name:tls-fingerprint
| +--rw map-type identityref
| +--rw name string
+--rw use-for enumeration
Each device records includes the device’s bootstrapping log, a history of interactions with the device.
The transport
configuration defines the listening ports SZTPD opens.
The following tree diagram illustrates the NBI used for configuring trust-anchors held in the truststore
.
+--rw truststore
+--rw certificate-bags! {ietf-truststore:certificates}?
+--rw certificate-bag* [name]
+--rw name string
+--rw description? string
+--rw certificate* [name]
| +--rw name string
| +--rw cert-data ietf-crypto-types:trust-anchor-cert-cms
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--ro reference-statistics
+--ro reference-count uint32
+--ro last-referenced union
The trust-anchors held in the truststore are use for many purposes (e.g., to authenticate clients, to authenticate remote systems, etc.).
This section presents the complete tree diagrams for Mode-1 and Mode-x (native). Modes ‘1’ and ‘x’ are discussed in the “First-time Initialization” section in the Installation Guide.
The tree diagrams provide an overview of the API’s data model but, for complete understanding of the YANG model, it is necessary to look at the YANG modules directly. The YANG modules are installed as part of the SZTPD package. Run the following command to discover the location for the YANG modules on your system:
python -c 'import pkg_resources; print(pkg_resources.resource_filename("sztpd", "yang/"))'
native
viewThe following tree diagram illustrates the entire NBI, from the perspective of the Mode ‘1’ native
interface.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
module: wn-sztpd-1
+--rw preferences
| +--rw admin-accounts
| | +--rw new-account-verification
| | | +--rw subject? string
| | | +--rw cc? string
| | | +--rw body? string
| | +--rw passwords
| | +--rw strength-testing!
| | +--rw min-length? uint16 <16>
| +--rw outbound-interactions
| | +--rw relay-notification-callout? -> ../../../dynamic-callouts/dynamic-callout/name
| | +--rw relay-progress-report-callout? -> ../../../dynamic-callouts/dynamic-callout/name
| +--rw system
| +--rw hostname? ietf-inet-types:host
| +--rw email-from-address? string <SZTPD Administrator <root@$SZTP-SERVER-ADDRESS>>
| +--rw features
| | +--rw onboarding-supported? boolean <true> {wn-sztpd-0:onboarding-supported}?
| +--rw plugins
| +--rw plugin* [name]
| +--rw name string
| +--rw functions
| +--rw function* [name]
| +--rw name string
+--rw admin-accounts
| +--rw admin-account* [email-address]
| +--rw email-address string
| +--rw fullname? string
| +--rw password iana-crypt-hash:crypt-hash
| +--ro password-last-modified ietf-yang-types:date-and-time
| +--rw access enumeration
| +---x resend-activation-email
+--ro audit-log
| +--ro log-entry*
| +--ro timestamp ietf-yang-types:date-and-time
| +--ro source-ip ietf-inet-types:ip-address
| +--ro source-proxies* string
| +--ro host string
| +--ro method enumeration
| +--ro path string
| +--ro outcome enumeration
| +--ro comment? string
+--rw truststore
| +--rw certificate-bags! {ietf-truststore:certificates}?
| +--rw certificate-bag* [name]
| +--rw name string
| +--rw description? string
| +--rw certificate* [name]
| | +--rw name string
| | +--rw cert-data ietf-crypto-types:trust-anchor-cert-cms
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw keystore {not system-level-administration-disabled}?
| +--rw asymmetric-keys
| | +--rw asymmetric-key* [name]
| | +--rw name string
| | +--rw public-key-format identityref
| | +--rw public-key binary
| | +--rw private-key-format? identityref
| | +--rw (private-key-type)
| | | +--:(cleartext-private-key)
| | | | +--rw cleartext-private-key? binary
| | | +--:(hidden-private-key)
| | | +--rw hidden-private-key? empty
| | +--rw certificates
| | | +--rw certificate* [name]
| | | +--rw name string
| | | +--rw cert-data ietf-crypto-types:end-entity-cert-cms
| | | +--ro reference-statistics
| | | +--ro reference-count uint32
| | | +--ro last-referenced union
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--rw symmetric-keys
| +--rw symmetric-key* [name]
| +--rw name string
| +--rw key-format? identityref
| +--rw (key-type)
| +--:(cleartext-key)
| | +--rw cleartext-key? binary
| +--:(hidden-key)
| +--rw hidden-key? empty
+--rw dynamic-callouts
| +--rw dynamic-callout* [name]
| +--rw name string
| +--rw rpc-supported identityref
| +--rw (callout-type)
| +--:(use-callback)
| +--rw callback
| | +--rw plugin -> /preferences/system/plugins/plugin/name
| | +--rw function -> /preferences/system/plugins/plugin[name = current()/../plugin]/functi\
ons/function/name
| +--rw opaque? anydata
+--rw transport {not system-level-administration-disabled}?
| +--rw listen! {ietf-restconf-server:http-listen or ietf-restconf-server:https-listen}?
| +--rw endpoint* [name]
| +--rw name string
| +--rw (transport)
| | +--:(http) {ietf-restconf-server:http-listen}?
| | | +--rw http
| | | +--rw external-endpoint!
| | | | +--rw address ietf-inet-types:ip-address
| | | | +--rw port? ietf-inet-types:port-number <443>
| | | +--rw tcp-server-parameters
| | | | +--rw local-address ietf-inet-types:ip-address
| | | | +--rw local-port? ietf-inet-types:port-number <80>
| | | +--rw http-server-parameters
| | | | +--rw server-name? string
| | | +--rw restconf-server-parameters
| | | +--rw client-identity-mappings
| | | +--rw cert-to-name* [id]
| | | +--rw id uint32
| | | +--rw fingerprint? ietf-x509-cert-to-name:tls-fingerprint
| | | +--rw map-type identityref
| | | +--rw name string
| | +--:(https) {ietf-restconf-server:https-listen}?
| | +--rw https
| | +--rw tcp-server-parameters
| | | +--rw local-address ietf-inet-types:ip-address
| | | +--rw local-port? ietf-inet-types:port-number <443>
| | +--rw tls-server-parameters
| | | +--rw server-identity
| | | | +--rw (auth-type)
| | | | +--:(certificate) {ietf-tls-server:x509-certificate-auth}?
| | | | +--rw certificate
| | | | +--rw (local-or-keystore)
| | | | +--:(local-keystore)
| | | | +--rw reference
| | | | +--rw asymmetric-key? -> /keystore/asymmetric-keys/asymmetric\
-key/name
| | | | +--rw certificate? -> /keystore/asymmetric-keys/asymmetric\
-key[name = current()/../asymmetric-key]/certificates/certificate/name
| | | +--rw client-authentication! {ietf-tls-server:client-auth-config-supported}?
| | | +--rw ca-certs! {ietf-tls-server:x509-certificate-auth}?
| | | | +--rw (local-or-truststore)
| | | | +--:(local-truststore) {ietf-truststore:certificates,ietf-tls-server:client\
-auth-config-supported}?
| | | | +--rw local-truststore-reference? -> /truststore/certificate-bags/cert\
ificate-bag/name
| | | +--rw ee-certs! {ietf-tls-server:x509-certificate-auth}?
| | | +--rw (local-or-truststore)
| | | +--:(local-truststore) {ietf-truststore:certificates,ietf-tls-server:client\
-auth-config-supported}?
| | | +--rw local-truststore-reference? -> /truststore/certificate-bags/cert\
ificate-bag/name
| | +--rw http-server-parameters
| | | +--rw server-name? string
| | +--rw restconf-server-parameters
| | +--rw client-identity-mappings
| | +--rw cert-to-name* [id]
| | +--rw id uint32
| | +--rw fingerprint? ietf-x509-cert-to-name:tls-fingerprint
| | +--rw map-type identityref
| | +--rw name string
| +--rw use-for enumeration
+--rw device-types
| +--rw device-type* [name]
| +--rw name string
| +--rw identity-certificates!
| | +--rw verification
| | | +--rw local-truststore-reference {ietf-truststore:certificates}?
| | | +--rw certificate-bag -> /truststore/certificate-bags/certificate-bag/name
| | | +--rw certificate -> /truststore/certificate-bags/certificate-bag[name = current()/\
../certificate-bag]/certificate/name
| | +--rw serial-number-extraction? identityref <wn-x509-c2n:serial-number>
| +--rw ownership-authorization!
| | +--rw dynamic-callout
| | +--rw reference? -> /dynamic-callouts/dynamic-callout/name
| +--rw voucher-aquisition!
| +--rw dynamic-callout
| +--rw reference? -> /dynamic-callouts/dynamic-callout/name
+--rw bootstrap-servers
| +--rw bootstrap-server* [name]
| +--rw name string
| +--rw address ietf-inet-types:host
| +--rw port? ietf-inet-types:port-number <443>
| +--rw trust-anchor? ietf-crypto-types:trust-anchor-cert-cms
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw boot-images {wn-sztpd-0:onboarding-supported}?
| +--rw boot-image* [name]
| +--rw name string
| +--rw os-name? string
| +--rw os-version? string
| +--rw download-uri* ietf-inet-types:uri
| +--rw image-verification* [hash-algorithm]
| | +--rw hash-algorithm identityref
| | +--rw hash-value ietf-yang-types:hex-string
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw scripts {wn-sztpd-0:onboarding-supported}?
| +--rw pre-configuration-script* [name]
| | +--rw name string
| | +--rw script? ietf-sztp-conveyed-info:script
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--rw post-configuration-script* [name]
| +--rw name string
| +--rw script? ietf-sztp-conveyed-info:script
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw configurations {wn-sztpd-0:onboarding-supported}?
| +--rw configuration* [name]
| +--rw name string
| +--rw configuration-handling? enumeration
| +--rw config? binary
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw conveyed-information-responses
| +--rw redirect-information-response* [name]
| | +--rw name string
| | +--rw redirect-information
| | | +--rw bootstrap-server* -> ../../../../bootstrap-servers/bootstrap-server/name
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--rw onboarding-information-response* [name] {wn-sztpd-0:onboarding-supported}?
| +--rw name string
| +--rw onboarding-information
| | +--rw boot-image -> ../../../../boot-images/boot-image/name
| | +--rw pre-configuration-script? -> ../../../../scripts/pre-configuration-script/name
| | +--rw configuration? -> ../../../../configurations/configuration/name
| | +--rw post-configuration-script? -> ../../../../scripts/post-configuration-script/name
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw devices
+--rw device* [serial-number]
+--rw serial-number string
+--rw activation-code? iana-crypt-hash:crypt-hash
+--rw response-manager
| +--rw matched-response* [name]
| +--rw name string
| +--rw match-criteria!
| | +--rw match* [key]
| | +--rw key string
| | +--rw not? empty
| | +--rw (test-type)
| | +--:(present)
| | | +--rw present? empty
| | +--:(value)
| | | +--rw value? string
| | +--:(regex)
| | +--rw regex? string
| +--rw response
| +--rw reporting-level? enumeration <minimal> {wn-sztpd-0:onboarding-supported}?
| +--rw (response-handler)
| +--:(none)
| | +--rw none? empty
| +--:(managed-response)
| +--rw conveyed-information
| +--rw (conveyed-information-handler)
| +--:(use-dynamic-callout)
| | +--rw dynamic-callout
| | +--rw reference? -> ../../../../../../../../dynamic-callouts/dynamic-c\
allout/name
| +--:(redirect-information)
| | +--rw redirect-information
| | +--rw (local-or-reference)
| | +--:(reference)
| | +--rw reference? -> ../../../../../../../../conveyed-information\
-responses/redirect-information-response/name
| +--:(onboarding-information) {wn-sztpd-0:onboarding-supported}?
| +--rw onboarding-information
| +--rw (local-or-reference)
| +--:(reference)
| +--rw reference? -> ../../../../../../../../conveyed-information\
-responses/onboarding-information-response/name
+--ro bootstrapping-log
| +--ro log-entry*
| +--ro timestamp ietf-yang-types:date-and-time
| +--ro source-ip ietf-inet-types:ip-address
| +--ro method string
| +--ro path string
| +--ro return-code uint16
| +--ro error-returned? anydata
| +--ro event-details
| +--ro (event-type)
| +--:(get-bootstrapping-data-event)
| | +--ro get-bootstrapping-data-event
| | +--ro passed-input anydata
| | +--ro selected-response? union
| | +--ro response-details
| | +--ro (response-type)
| | +--:(managed-response)
| | +--ro managed-response
| | +--ro conveyed-information
| | +--ro (conveyed-information-handler)
| | +--:(dynamic-callout)
| | | +--ro dynamic-callout
| | | +--ro (result-type)?
| | | +--:(no-callout-configured)
| | | | +--ro no-callout-configured? empty
| | | +--:(callout-configured)
| | | +--ro name string
| | | +--ro rpc-supported identityref
| | | +--ro callout-type enumeration
| | | +--ro (callback-or-webhook)?
| | | +--:(callback)
| | | +--ro callback-details
| | | | +--ro plugin string
| | | | +--ro function string
| | | +--ro callback-results
| | | +--ro (exit-status)
| | | +--:(exception-thrown)
| | | | +--ro exception-thrown? string
| | | +--:(exited-normally)
| | | +--ro exited-normally? string
| | +--:(redirect-information)
| | | +--ro redirect-information
| | | +--ro (local-or-reference)
| | | +--:(reference)
| | | +--ro referenced-definition? string
| | +--:(onboarding-information) {wn-sztpd-0:onboarding-supported}?
| | +--ro onboarding-information
| | +--ro (local-or-reference)
| | +--:(reference)
| | +--ro referenced-definition? string
| +--:(report-progress-event) {wn-sztpd-0:onboarding-supported}?
| +--ro report-progress-event
| +--ro passed-input anydata
| +--ro dynamic-callout
| +--ro (result-type)?
| +--:(no-callout-configured)
| | +--ro no-callout-configured? empty
| +--:(callout-configured)
| +--ro name string
| +--ro rpc-supported identityref
| +--ro callout-type enumeration
| +--ro (callback-or-webhook)?
| +--:(callback)
| +--ro callback-details
| | +--ro plugin string
| | +--ro function string
| +--ro callback-results
| +--ro (exit-status)
| +--:(exception-thrown)
| | +--ro exception-thrown? string
| +--:(exited-normally)
| +--ro exited-normally? string
+--ro lifecycle-statistics
| +--ro nbi-access-stats
| | +--ro created ietf-yang-types:date-and-time
| | +--ro num-times-modified uint16
| | +--ro last-modified ietf-yang-types:date-and-time
| +--ro sbi-access-stats
| +--ro num-times-accessed uint16
| +--ro first-accessed ietf-yang-types:date-and-time
| +--ro last-accessed ietf-yang-types:date-and-time
+--rw device-type -> /device-types/device-type/name
native
viewThe following tree diagram illustrates the entire NBI, from the perspective of the Mode ‘x’ native
interface (not the tenant
interface.
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
module: wn-sztpd-x
+--rw device-types
| +--rw device-type* [name]
| +--rw name string
| +--rw identity-certificates!
| | +--rw verification
| | | +--rw local-truststore-reference {ietf-truststore:certificates}?
| | | +--rw certificate-bag -> /truststore/certificate-bags/certificate-bag/name
| | | +--rw certificate -> /truststore/certificate-bags/certificate-bag[name = current()/\
../certificate-bag]/certificate/name
| | +--rw serial-number-extraction? identityref <wn-x509-c2n:serial-number>
| +--rw ownership-authorization!
| | +--rw dynamic-callout
| | +--rw reference? -> /dynamic-callouts/dynamic-callout/name
| +--rw voucher-aquisition!
| +--rw dynamic-callout
| +--rw reference? -> /dynamic-callouts/dynamic-callout/name
+--rw preferences
| +--rw admin-accounts
| | +--rw new-account-verification
| | | +--rw subject? string
| | | +--rw cc? string
| | | +--rw body? string
| | +--rw passwords
| | +--rw strength-testing!
| | +--rw min-length? uint16 <16>
| +--rw outbound-interactions
| | +--rw relay-notification-callout? -> ../../../dynamic-callouts/dynamic-callout/name
| | +--rw relay-progress-report-callout? -> ../../../dynamic-callouts/dynamic-callout/name
| +--rw system
| +--rw hostname? ietf-inet-types:host
| +--rw email-from-address? string <SZTPD Administrator <root@$SZTP-SERVER-ADDRESS>>
| +--rw features
| | +--rw onboarding-supported? boolean <true> {wn-sztpd-0:onboarding-supported}?
| +--rw plugins
| +--rw plugin* [name]
| +--rw name string
| +--rw functions
| +--rw function* [name]
| +--rw name string
+--rw admin-accounts
| +--rw admin-account* [email-address]
| +--rw email-address string
| +--rw fullname? string
| +--rw password iana-crypt-hash:crypt-hash
| +--ro password-last-modified ietf-yang-types:date-and-time
| +--rw access enumeration
| +---x resend-activation-email
+--ro audit-log
| +--ro log-entry*
| +--ro timestamp ietf-yang-types:date-and-time
| +--ro source-ip ietf-inet-types:ip-address
| +--ro source-proxies* string
| +--ro host string
| +--ro method enumeration
| +--ro path string
| +--ro outcome enumeration
| +--ro comment? string
+--rw truststore
| +--rw certificate-bags! {ietf-truststore:certificates}?
| +--rw certificate-bag* [name]
| +--rw name string
| +--rw description? string
| +--rw certificate* [name]
| | +--rw name string
| | +--rw cert-data ietf-crypto-types:trust-anchor-cert-cms
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw keystore
| +--rw asymmetric-keys
| | +--rw asymmetric-key* [name]
| | +--rw name string
| | +--rw public-key-format identityref
| | +--rw public-key binary
| | +--rw private-key-format? identityref
| | +--rw (private-key-type)
| | | +--:(cleartext-private-key)
| | | | +--rw cleartext-private-key? binary
| | | +--:(hidden-private-key)
| | | +--rw hidden-private-key? empty
| | +--rw certificates
| | | +--rw certificate* [name]
| | | +--rw name string
| | | +--rw cert-data ietf-crypto-types:end-entity-cert-cms
| | | +--ro reference-statistics
| | | +--ro reference-count uint32
| | | +--ro last-referenced union
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--rw symmetric-keys
| +--rw symmetric-key* [name]
| +--rw name string
| +--rw key-format? identityref
| +--rw (key-type)
| +--:(cleartext-key)
| | +--rw cleartext-key? binary
| +--:(hidden-key)
| +--rw hidden-key? empty
+--rw dynamic-callouts
| +--rw dynamic-callout* [name]
| +--rw name string
| +--rw rpc-supported identityref
| +--rw (callout-type)
| +--:(use-callback)
| +--rw callback
| | +--rw plugin -> /preferences/system/plugins/plugin/name
| | +--rw function -> /preferences/system/plugins/plugin[name = current()/../plugin]/functi\
ons/function/name
| +--rw opaque? anydata
+--rw transport
| +--rw listen! {ietf-restconf-server:http-listen or ietf-restconf-server:https-listen}?
| +--rw endpoint* [name]
| +--rw name string
| +--rw (transport)
| | +--:(http) {ietf-restconf-server:http-listen}?
| | | +--rw http
| | | +--rw external-endpoint!
| | | | +--rw address ietf-inet-types:ip-address
| | | | +--rw port? ietf-inet-types:port-number <443>
| | | +--rw tcp-server-parameters
| | | | +--rw local-address ietf-inet-types:ip-address
| | | | +--rw local-port? ietf-inet-types:port-number <80>
| | | +--rw http-server-parameters
| | | | +--rw server-name? string
| | | +--rw restconf-server-parameters
| | | +--rw client-identity-mappings
| | | +--rw cert-to-name* [id]
| | | +--rw id uint32
| | | +--rw fingerprint? ietf-x509-cert-to-name:tls-fingerprint
| | | +--rw map-type identityref
| | | +--rw name string
| | +--:(https) {ietf-restconf-server:https-listen}?
| | +--rw https
| | +--rw tcp-server-parameters
| | | +--rw local-address ietf-inet-types:ip-address
| | | +--rw local-port? ietf-inet-types:port-number <443>
| | +--rw tls-server-parameters
| | | +--rw server-identity
| | | | +--rw (auth-type)
| | | | +--:(certificate) {ietf-tls-server:x509-certificate-auth}?
| | | | +--rw certificate
| | | | +--rw (local-or-keystore)
| | | | +--:(local-keystore)
| | | | +--rw reference
| | | | +--rw asymmetric-key? -> /keystore/asymmetric-keys/asymmetric\
-key/name
| | | | +--rw certificate? -> /keystore/asymmetric-keys/asymmetric\
-key[name = current()/../asymmetric-key]/certificates/certificate/name
| | | +--rw client-authentication! {ietf-tls-server:client-auth-config-supported}?
| | | +--rw ca-certs! {ietf-tls-server:x509-certificate-auth}?
| | | | +--rw (local-or-truststore)
| | | | +--:(local-truststore) {ietf-truststore:certificates,ietf-tls-server:client\
-auth-config-supported}?
| | | | +--rw local-truststore-reference? -> /truststore/certificate-bags/cert\
ificate-bag/name
| | | +--rw ee-certs! {ietf-tls-server:x509-certificate-auth}?
| | | +--rw (local-or-truststore)
| | | +--:(local-truststore) {ietf-truststore:certificates,ietf-tls-server:client\
-auth-config-supported}?
| | | +--rw local-truststore-reference? -> /truststore/certificate-bags/cert\
ificate-bag/name
| | +--rw http-server-parameters
| | | +--rw server-name? string
| | +--rw restconf-server-parameters
| | +--rw client-identity-mappings
| | +--rw cert-to-name* [id]
| | +--rw id uint32
| | +--rw fingerprint? ietf-x509-cert-to-name:tls-fingerprint
| | +--rw map-type identityref
| | +--rw name string
| +--rw use-for enumeration
+--rw tenants
+--rw tenant* [name]
+--rw name string
+--rw preferences
| +--rw admin-accounts
| | +--rw new-account-verification
| | | +--rw subject? string
| | | +--rw cc? string
| | | +--rw body? string
| | +--rw passwords
| | +--rw strength-testing!
| | +--rw min-length? uint16 <16>
| +--rw outbound-interactions
| +--rw relay-notification-callout? -> ../../../dynamic-callouts/dynamic-callout/name
| +--rw relay-progress-report-callout? -> ../../../dynamic-callouts/dynamic-callout/name
+--rw admin-accounts
| +--rw admin-account* [email-address]
| +--rw email-address string
| +--rw fullname? string
| +--rw password iana-crypt-hash:crypt-hash
| +--ro password-last-modified ietf-yang-types:date-and-time
| +--rw access enumeration
| +---x resend-activation-email
+--ro audit-log
| +--ro log-entry*
| +--ro timestamp ietf-yang-types:date-and-time
| +--ro source-ip ietf-inet-types:ip-address
| +--ro source-proxies* string
| +--ro host string
| +--ro method enumeration
| +--ro path string
| +--ro outcome enumeration
| +--ro comment? string
+--rw truststore
| +--rw certificate-bags! {ietf-truststore:certificates}?
| +--rw certificate-bag* [name]
| +--rw name string
| +--rw description? string
| +--rw certificate* [name]
| | +--rw name string
| | +--rw cert-data ietf-crypto-types:trust-anchor-cert-cms
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw keystore
| +--rw asymmetric-keys
| | +--rw asymmetric-key* [name]
| | +--rw name string
| | +--rw public-key-format identityref
| | +--rw public-key binary
| | +--rw private-key-format? identityref
| | +--rw (private-key-type)
| | | +--:(cleartext-private-key)
| | | | +--rw cleartext-private-key? binary
| | | +--:(hidden-private-key)
| | | +--rw hidden-private-key? empty
| | +--rw certificates
| | | +--rw certificate* [name]
| | | +--rw name string
| | | +--rw cert-data ietf-crypto-types:end-entity-cert-cms
| | | +--ro reference-statistics
| | | +--ro reference-count uint32
| | | +--ro last-referenced union
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--rw symmetric-keys
| +--rw symmetric-key* [name]
| +--rw name string
| +--rw key-format? identityref
| +--rw (key-type)
| +--:(cleartext-key)
| | +--rw cleartext-key? binary
| +--:(hidden-key)
| +--rw hidden-key? empty
+--rw dynamic-callouts
| +--rw dynamic-callout* [name]
| +--rw name string
| +--rw rpc-supported identityref
| +--rw (callout-type)
| +--:(use-callback)
| +--rw callback
| | +--rw plugin -> /preferences/system/plugins/plugin/name
| | +--rw function -> /preferences/system/plugins/plugin[name = current()/../plugin]/\
functions/function/name
| +--rw opaque? anydata
+--rw bootstrap-servers
| +--rw bootstrap-server* [name]
| +--rw name string
| +--rw address ietf-inet-types:host
| +--rw port? ietf-inet-types:port-number <443>
| +--rw trust-anchor? ietf-crypto-types:trust-anchor-cert-cms
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw boot-images {wn-sztpd-0:onboarding-supported}?
| +--rw boot-image* [name]
| +--rw name string
| +--rw os-name? string
| +--rw os-version? string
| +--rw download-uri* ietf-inet-types:uri
| +--rw image-verification* [hash-algorithm]
| | +--rw hash-algorithm identityref
| | +--rw hash-value ietf-yang-types:hex-string
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw scripts {wn-sztpd-0:onboarding-supported}?
| +--rw pre-configuration-script* [name]
| | +--rw name string
| | +--rw script? ietf-sztp-conveyed-info:script
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--rw post-configuration-script* [name]
| +--rw name string
| +--rw script? ietf-sztp-conveyed-info:script
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw configurations {wn-sztpd-0:onboarding-supported}?
| +--rw configuration* [name]
| +--rw name string
| +--rw configuration-handling? enumeration
| +--rw config? binary
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw conveyed-information-responses
| +--rw redirect-information-response* [name]
| | +--rw name string
| | +--rw redirect-information
| | | +--rw bootstrap-server* -> ../../../../bootstrap-servers/bootstrap-server/name
| | +--ro reference-statistics
| | +--ro reference-count uint32
| | +--ro last-referenced union
| +--rw onboarding-information-response* [name] {wn-sztpd-0:onboarding-supported}?
| +--rw name string
| +--rw onboarding-information
| | +--rw boot-image -> ../../../../boot-images/boot-image/name
| | +--rw pre-configuration-script? -> ../../../../scripts/pre-configuration-script/name
| | +--rw configuration? -> ../../../../configurations/configuration/name
| | +--rw post-configuration-script? -> ../../../../scripts/post-configuration-script/name
| +--ro reference-statistics
| +--ro reference-count uint32
| +--ro last-referenced union
+--rw devices
+--rw device* [serial-number]
+--rw serial-number string
+--rw activation-code? iana-crypt-hash:crypt-hash
+--rw response-manager
| +--rw matched-response* [name]
| +--rw name string
| +--rw match-criteria!
| | +--rw match* [key]
| | +--rw key string
| | +--rw not? empty
| | +--rw (test-type)
| | +--:(present)
| | | +--rw present? empty
| | +--:(value)
| | | +--rw value? string
| | +--:(regex)
| | +--rw regex? string
| +--rw response
| +--rw reporting-level? enumeration <minimal> {wn-sztpd-0:onboarding-supported}?
| +--rw (response-handler)
| +--:(none)
| | +--rw none? empty
| +--:(managed-response)
| +--rw conveyed-information
| +--rw (conveyed-information-handler)
| +--:(use-dynamic-callout)
| | +--rw dynamic-callout
| | +--rw reference? -> ../../../../../../../../dynamic-callouts/dyn\
amic-callout/name
| +--:(redirect-information)
| | +--rw redirect-information
| | +--rw (local-or-reference)
| | +--:(reference)
| | +--rw reference? -> ../../../../../../../../conveyed-infor\
mation-responses/redirect-information-response/name
| +--:(onboarding-information) {wn-sztpd-0:onboarding-supported}?
| +--rw onboarding-information
| +--rw (local-or-reference)
| +--:(reference)
| +--rw reference? -> ../../../../../../../../conveyed-infor\
mation-responses/onboarding-information-response/name
+--ro bootstrapping-log
| +--ro log-entry*
| +--ro timestamp ietf-yang-types:date-and-time
| +--ro source-ip ietf-inet-types:ip-address
| +--ro method string
| +--ro path string
| +--ro return-code uint16
| +--ro error-returned? anydata
| +--ro event-details
| +--ro (event-type)
| +--:(get-bootstrapping-data-event)
| | +--ro get-bootstrapping-data-event
| | +--ro passed-input anydata
| | +--ro selected-response? union
| | +--ro response-details
| | +--ro (response-type)
| | +--:(managed-response)
| | +--ro managed-response
| | +--ro conveyed-information
| | +--ro (conveyed-information-handler)
| | +--:(dynamic-callout)
| | | +--ro dynamic-callout
| | | +--ro (result-type)?
| | | +--:(no-callout-configured)
| | | | +--ro no-callout-configured? empty
| | | +--:(callout-configured)
| | | +--ro name string
| | | +--ro rpc-supported identityref
| | | +--ro callout-type enumeration
| | | +--ro (callback-or-webhook)?
| | | +--:(callback)
| | | +--ro callback-details
| | | | +--ro plugin string
| | | | +--ro function string
| | | +--ro callback-results
| | | +--ro (exit-status)
| | | +--:(exception-thrown)
| | | | +--ro exception-thrown? stri\
ng
| | | +--:(exited-normally)
| | | +--ro exited-normally? string
| | +--:(redirect-information)
| | | +--ro redirect-information
| | | +--ro (local-or-reference)
| | | +--:(reference)
| | | +--ro referenced-definition? string
| | +--:(onboarding-information) {wn-sztpd-0:onboarding-suppo\
rted}?
| | +--ro onboarding-information
| | +--ro (local-or-reference)
| | +--:(reference)
| | +--ro referenced-definition? string
| +--:(report-progress-event) {wn-sztpd-0:onboarding-supported}?
| +--ro report-progress-event
| +--ro passed-input anydata
| +--ro dynamic-callout
| +--ro (result-type)?
| +--:(no-callout-configured)
| | +--ro no-callout-configured? empty
| +--:(callout-configured)
| +--ro name string
| +--ro rpc-supported identityref
| +--ro callout-type enumeration
| +--ro (callback-or-webhook)?
| +--:(callback)
| +--ro callback-details
| | +--ro plugin string
| | +--ro function string
| +--ro callback-results
| +--ro (exit-status)
| +--:(exception-thrown)
| | +--ro exception-thrown? string
| +--:(exited-normally)
| +--ro exited-normally? string
+--ro lifecycle-statistics
| +--ro nbi-access-stats
| | +--ro created ietf-yang-types:date-and-time
| | +--ro num-times-modified uint16
| | +--ro last-modified ietf-yang-types:date-and-time
| +--ro sbi-access-stats
| +--ro num-times-accessed uint16
| +--ro first-accessed ietf-yang-types:date-and-time
| +--ro last-accessed ietf-yang-types:date-and-time
+--rw device-type -> /device-types/device-type/name
The southbound interface implements the “bootstrap server” defined in RFC 8572.
This section is used primarily to illustrate usage for developers.
Just as with the NBI, described by Fetching Host-meta, a command can be sent to the sent to the SBI to detemine the RESTCONF server’s root prefix. For the purpose of this tutorial, assume that the response is the same as shown for the NBI.
Just as with the NBI, described by Determining the Encodings Supported, a command can be sent to the SBI to demine what encodings the server supports, shown below in XML. Note that no “Content-Type” header was included though required for a GET command, and an “Accept” header is returned, indicating that both JSON and XML are supported.
Request:
$ curl -i http://127.0.0.1:8080/restconf
Response:
HTTP/1.1 400 Bad Request
Accept: application/yang-data+json, application/yang-data+xml
Accept-Charset: utf-8
Content-Type: text/plain; charset=utf-8
Server: <redacted>
Content-Length: 191
Date: Tue, 15 Dec 2020 20:01:03 GMT
Unable to determine response encoding. An "Accept" value must be specified for
this resource. The "Accept" value must be either "application/yang-data+json"
or "application/yang-data+xml".
Just as in Fetching the RESTCONF Root Resource, a command can be sent to the SBI to demine what encodings the server supports, shown below in XML
Request:
$ curl -i -H "Accept:application/yang-data+xml" http://127.0.0.1:8080/restconf/
Response:
HTTP/1.1 200 OK
Content-Type: application/yang-data+xml; charset=utf-8
Server: <redacted>
Content-Length: 163
Date: Tue, 15 Dec 2020 20:00:19 GMT
<restconf xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
<data/>
<operations/>
<yang-library-version>2016-06-21</yang-library-version>
</restconf>
Request:
================================== NOTE: '\\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.xml
<input xmlns="urn:ietf:params:xml:ns:yang:ietf-sztp-bootstrap-server">
<hw-model>model-x</hw-model>
<os-name>vendor-os</os-name>
<os-version>17.3R2.1</os-version>
<nonce>BASE64VALUE=</nonce>
</input>
EOM
# POST 'input' for the "get-bootstrapping-data" RPC resource
curl -i -X POST --data @input.xml -H "Content-Type:application/yang-data+xml" --cacert sbi_trust_chain.pem \
\--key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-numb\
\er:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data \
\1> output/post_rpc_input_xml.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_rpc_input_xml.out
# cleanup
rm -f input.xml
Response:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 200 OK
Content-Type: application/yang-data+xml; charset=utf-8
Content-Length: 2993
Date: Fri, 15 Jan 2021 02:38:09 GMT
Server: <redacted>
<?xml version="1.0" ?>
<output xmlns="urn:ietf:params:xml:ns:yang:ietf-sztp-bootstrap-server">
<conveyed-information>MIIITAYLKoZIhvcNAQkQASqgggg7BIIINzw/eG1sIHZlcnNpb249IjEuMCIgPz4KPGNvbnRlbnQtZGF0YSB\
4bWxucz0idXJuOmlldGY6cGFyYW1zOnhtbDpuczp5YW5nOmlldGYteWFuZy1pbnN0YW5jZS1kYXRhIj4KICA8cmVkaXJlY3QtaW5mb3JtYX\
Rpb24geG1sbnM9InVybjppZXRmOnBhcmFtczp4bWw6bnM6eWFuZzppZXRmLXN6dHAtY29udmV5ZWQtaW5mbyI+CiAgICA8Ym9vdHN0cmFwL\
XNlcnZlcj4KICAgICAgPGFkZHJlc3M+MTI3LjAuMC4xPC9hZGRyZXNzPgogICAgICA8cG9ydD45NDQzPC9wb3J0PgogICAgICA8dHJ1c3Qt\
YW5jaG9yPk1JSUZFUVlKS29aSWh2Y05BUWNDb0lJRkFqQ0NCUDRDQVFFeEFEQUxCZ2txaGtpRzl3MEJCd0dnZ2dUa01JSUNXakNDQWYrZ0F\
3SUJBZ0lCQVRBS0JnZ3Foa2pPUFFRREFqQjFNUXN3Q1FZRFZRUUdFd0pZV0RFZE1Cc0dBMVVFQ0F3VVRYa2dVM1JoZEdVZ2IzSWdVSEp2ZG\
1sdVkyVXhHREFXQmdOVkJBb01EMDE1SUU5eVoyRnVhWHBoZEdsdmJqRVFNQTRHQTFVRUN3d0hUWGtnVlc1cGRERWJNQmtHQTFVRUF3d1NjM\
kpwTDNObGNuWmxjaTl5YjI5MExXTmhNQ0FYRFRJd01Ea3hPREl3TVRrME5Gb1lEems1T1RreE1qTXhNak0xT1RVNVdqQjFNUXN3Q1FZRFZR\
UUdFd0pZV0RFZE1Cc0dBMVVFQ0F3VVRYa2dVM1JoZEdVZ2IzSWdVSEp2ZG1sdVkyVXhHREFXQmdOVkJBb01EMDE1SUU5eVoyRnVhWHBoZEd\
sdmJqRVFNQTRHQTFVRUN3d0hUWGtnVlc1cGRERWJNQmtHQTFVRUF3d1NjMkpwTDNObGNuWmxjaTl5YjI5MExXTmhNRmt3RXdZSEtvWkl6aj\
BDQVFZSUtvWkl6ajBEQVFjRFFnQUUwdURDOWRWTFpJTkluTit4SnRvR1prRk5lMVVPWFpNS0phVVdFYnVxaDNVTFowNXVnRUZkSFZnNVpJc\
0dwRllXRldlRTFPK0wycVBid1lGaUxXY1R6S04rTUh3d0hRWURWUjBPQkJZRUZLaGI5MkZWRFp6QkpwaEdjeUQvV1NBb1VYWVlNQXdHQTFV\
ZEV3UUZNQU1CQWY4d0RnWURWUjBQQVFIL0JBUURBZ0VHTUQwR0ExVWRId1EyTURRd01xQXdvQzZHTEdoMGRIQTZMeTlqY213dVpYaGhiWEJ\
zWlM1amIyMC9ZMkU5YzJKcE9uTmxjblpsY2pweWIyOTBMV05oTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDSVFDWHQ4NENJelRjZTloS1p1WE\
dhSi9TMVA5WUxMbnE2dkQyWW5iOGh1RFJvQUloQUpFWjZqQWxiSmpjOVVQVlRHeURFaElnNmtzdmdZSDEvYnlJOXFacWxGdmZNSUlDZ2pDQ\
0FpaWdBd0lCQWdJQkFqQUtCZ2dxaGtqT1BRUURBakIxTVFzd0NRWURWUVFHRXdKWVdERWRNQnNHQTFVRUNBd1VUWGtnVTNSaGRHVWdiM0ln\
VUhKdmRtbHVZMlV4R0RBV0JnTlZCQW9NRDAxNUlFOXlaMkZ1YVhwaGRHbHZiakVRTUE0R0ExVUVDd3dIVFhrZ1ZXNXBkREViTUJrR0ExVUV\
Bd3dTYzJKcEwzTmxjblpsY2k5eWIyOTBMV05oTUNBWERUSXdNRGt4T0RJd01UazBOVm9ZRHprNU9Ua3hNak14TWpNMU9UVTVXakI3TVFzd0\
NRWURWUVFHRXdKWVdERWRNQnNHQTFVRUNBd1VUWGtnVTNSaGRHVWdiM0lnVUhKdmRtbHVZMlV4R0RBV0JnTlZCQW9NRDAxNUlFOXlaMkZ1Y\
VhwaGRHbHZiakVRTUE0R0ExVUVDd3dIVFhrZ1ZXNXBkREVoTUI4R0ExVUVBd3dZYzJKcEwzTmxjblpsY2k5cGJuUmxjbTFsWkdsaGRHVXhN\
Rmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUV3TzJVZkw5MVp6TWt5WS8xSW4vM2QxQzJHSDZMM3IxRFNQc2RETWFsbFJHSTJ\
TTFVBTTlxRGRDbmZXb01UcnZwbmJuZXZqOXFRdEdaU25vMHNHTFNiNk9Cb0RDQm5UQWRCZ05WSFE0RUZnUVVpRnNHVFZSc2ZNNElqaDRkRH\
pWbWdDTlJxT3N3SHdZRFZSMGpCQmd3Rm9BVXFGdjNZVlVObk1FbW1FWnpJUDlaSUNoUmRoZ3dEQVlEVlIwVEJBVXdBd0VCL3pBT0JnTlZIU\
ThCQWY4RUJBTUNBUVl3UFFZRFZSMGZCRFl3TkRBeW9EQ2dMb1lzYUhSMGNEb3ZMMk55YkM1bGVHRnRjR3hsTG1OdmJUOWpZVDF6WW1rNmMy\
VnlkbVZ5T25KdmIzUXRZMkV3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQU5sUFQxcHBEWjBwZXMyU2gvajJJZzRBVkNNakE1SkZsQ2JyVEJ\
qODBrZEpBaUFEQzVnRXhXM1hxb0ViekpNMDJsRFU3YkkyRmRrV09qVjZzRWppODE3dVg2RUFNUUE9PC90cnVzdC1hbmNob3I+CiAgICA8L2\
Jvb3RzdHJhcC1zZXJ2ZXI+CiAgPC9yZWRpcmVjdC1pbmZvcm1hdGlvbj4KPC9jb250ZW50LWRhdGE+Cg==</conveyed-information>
</output>
Request:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.json
{
"ietf-sztp-bootstrap-server:input" : {
"hw-model" : "model-x",
"os-name" : "vendor-os",
"os-version" : "17.3R2.1",
"nonce" : "BASE64VALUE="
}
}
EOM
# POST 'input' for the "get-bootstrapping-data" RPC resource
curl -i -X POST --data @input.json -H "Content-Type:application/yang-data+json" --cacert sbi_trust_chain.pe\
m --key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-num\
ber:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data \
1> output/post_rpc_input.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_rpc_input.out
# cleanup
rm -f input.json
Response:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 2679
Date: Fri, 15 Jan 2021 02:38:09 GMT
Server: <redacted>
{
"ietf-sztp-bootstrap-server:output": {
"conveyed-information": "MIIHmQYLKoZIhvcNAQkQASugggeIBIIHhHsKICAiaWV0Zi1zenRwLWNvbnZleWVkLWluZm86cmVkaX\
JlY3QtaW5mb3JtYXRpb24iOiB7CiAgICAiYm9vdHN0cmFwLXNlcnZlciI6IFsKICAgICAgewogICAgICAgICJhZGRyZXNzIjogIjEyNy4wL\
jAuMSIsCiAgICAgICAgInBvcnQiOiA5NDQzLAogICAgICAgICJ0cnVzdC1hbmNob3IiOiAiTUlJRkVRWUpLb1pJaHZjTkFRY0NvSUlGQWpD\
Q0JQNENBUUV4QURBTEJna3Foa2lHOXcwQkJ3R2dnZ1RrTUlJQ1dqQ0NBZitnQXdJQkFnSUJBVEFLQmdncWhrak9QUVFEQWpCMU1Rc3dDUVl\
EVlFRR0V3SllXREVkTUJzR0ExVUVDQXdVVFhrZ1UzUmhkR1VnYjNJZ1VISnZkbWx1WTJVeEdEQVdCZ05WQkFvTUQwMTVJRTl5WjJGdWFYcG\
hkR2x2YmpFUU1BNEdBMVVFQ3d3SFRYa2dWVzVwZERFYk1Ca0dBMVVFQXd3U2MySnBMM05sY25abGNpOXliMjkwTFdOaE1DQVhEVEl3TURre\
E9ESXdNVGswTkZvWUR6azVPVGt4TWpNeE1qTTFPVFU1V2pCMU1Rc3dDUVlEVlFRR0V3SllXREVkTUJzR0ExVUVDQXdVVFhrZ1UzUmhkR1Vn\
YjNJZ1VISnZkbWx1WTJVeEdEQVdCZ05WQkFvTUQwMTVJRTl5WjJGdWFYcGhkR2x2YmpFUU1BNEdBMVVFQ3d3SFRYa2dWVzVwZERFYk1Ca0d\
BMVVFQXd3U2MySnBMM05sY25abGNpOXliMjkwTFdOaE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTB1REM5ZFZMWklOSW\
5OK3hKdG9HWmtGTmUxVU9YWk1LSmFVV0VidXFoM1VMWjA1dWdFRmRIVmc1WklzR3BGWVdGV2VFMU8rTDJxUGJ3WUZpTFdjVHpLTitNSHd3S\
FFZRFZSME9CQllFRktoYjkyRlZEWnpCSnBoR2N5RC9XU0FvVVhZWU1Bd0dBMVVkRXdRRk1BTUJBZjh3RGdZRFZSMFBBUUgvQkFRREFnRUdN\
RDBHQTFVZEh3UTJNRFF3TXFBd29DNkdMR2gwZEhBNkx5OWpjbXd1WlhoaGJYQnNaUzVqYjIwL1kyRTljMkpwT25ObGNuWmxjanB5YjI5MEx\
XTmhNQW9HQ0NxR1NNNDlCQU1DQTBrQU1FWUNJUUNYdDg0Q0l6VGNlOWhLWnVYR2FKL1MxUDlZTExucTZ2RDJZbmI4aHVEUm9BSWhBSkVaNm\
pBbGJKamM5VVBWVEd5REVoSWc2a3N2Z1lIMS9ieUk5cVpxbEZ2Zk1JSUNnakNDQWlpZ0F3SUJBZ0lCQWpBS0JnZ3Foa2pPUFFRREFqQjFNU\
XN3Q1FZRFZRUUdFd0pZV0RFZE1Cc0dBMVVFQ0F3VVRYa2dVM1JoZEdVZ2IzSWdVSEp2ZG1sdVkyVXhHREFXQmdOVkJBb01EMDE1SUU5eVoy\
RnVhWHBoZEdsdmJqRVFNQTRHQTFVRUN3d0hUWGtnVlc1cGRERWJNQmtHQTFVRUF3d1NjMkpwTDNObGNuWmxjaTl5YjI5MExXTmhNQ0FYRFR\
Jd01Ea3hPREl3TVRrME5Wb1lEems1T1RreE1qTXhNak0xT1RVNVdqQjdNUXN3Q1FZRFZRUUdFd0pZV0RFZE1Cc0dBMVVFQ0F3VVRYa2dVM1\
JoZEdVZ2IzSWdVSEp2ZG1sdVkyVXhHREFXQmdOVkJBb01EMDE1SUU5eVoyRnVhWHBoZEdsdmJqRVFNQTRHQTFVRUN3d0hUWGtnVlc1cGRER\
WhNQjhHQTFVRUF3d1ljMkpwTDNObGNuWmxjaTlwYm5SbGNtMWxaR2xoZEdVeE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdB\
RXdPMlVmTDkxWnpNa3lZLzFJbi8zZDFDMkdINkwzcjFEU1BzZERNYWxsUkdJMlNMVUFNOXFEZENuZldvTVRydnBuYm5ldmo5cVF0R1pTbm8\
wc0dMU2I2T0JvRENCblRBZEJnTlZIUTRFRmdRVWlGc0dUVlJzZk00SWpoNGREelZtZ0NOUnFPc3dId1lEVlIwakJCZ3dGb0FVcUZ2M1lWVU\
5uTUVtbUVaeklQOVpJQ2hSZGhnd0RBWURWUjBUQkFVd0F3RUIvekFPQmdOVkhROEJBZjhFQkFNQ0FRWXdQUVlEVlIwZkJEWXdOREF5b0RDZ\
0xvWXNhSFIwY0RvdkwyTnliQzVsZUdGdGNHeGxMbU52YlQ5allUMXpZbWs2YzJWeWRtVnlPbkp2YjNRdFkyRXdDZ1lJS29aSXpqMEVBd0lE\
U0FBd1JRSWhBTmxQVDFwcERaMHBlczJTaC9qMklnNEFWQ01qQTVKRmxDYnJUQmo4MGtkSkFpQURDNWdFeFczWHFvRWJ6Sk0wMmxEVTdiSTJ\
GZGtXT2pWNnNFamk4MTd1WDZFQU1RQT0iCiAgICAgIH0KICAgIF0KICB9Cn0="
}
}
Request:
================================== NOTE: '\\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.xml
<input xmlns="urn:ietf:params:xml:ns:yang:ietf-sztp-bootstrap-server">
<hw-model>model-x</hw-model>
<os-name>vendor-os</os-name>
<os-version>17.3R2.1</os-version>
<nonce>BASE64VALUE=</nonce>
</input>
EOM
# POST 'input' for the "get-bootstrapping-data" RPC resource
curl -i -X POST --data @input.xml -H "Content-Type:application/yang-data+xml" --cacert sbi_trust_chain.pem \
\--key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-numb\
\er:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data \
\1> output/post_rpc_input_xml.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_rpc_input_xml.out
# cleanup
rm -f input.xml
Response:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 200 OK
Content-Type: application/yang-data+xml; charset=utf-8
Content-Length: 1605
Date: Fri, 15 Jan 2021 02:38:11 GMT
Server: <redacted>
<?xml version="1.0" ?>
<output xmlns="urn:ietf:params:xml:ns:yang:ietf-sztp-bootstrap-server">
<conveyed-information>MIIEPAYLKoZIhvcNAQkQASqgggQrBIIEJzw/eG1sIHZlcnNpb249IjEuMCIgPz4KPGNvbnRlbnQtZGF0YSB\
4bWxucz0idXJuOmlldGY6cGFyYW1zOnhtbDpuczp5YW5nOmlldGYteWFuZy1pbnN0YW5jZS1kYXRhIj4KICA8b25ib2FyZGluZy1pbmZvcm\
1hdGlvbiB4bWxucz0idXJuOmlldGY6cGFyYW1zOnhtbDpuczp5YW5nOmlldGYtc3p0cC1jb252ZXllZC1pbmZvIj4KICAgIDxib290LWltY\
WdlPgogICAgICA8ZG93bmxvYWQtdXJpPmh0dHBzOi8vZXhhbXBsZS5jb20vbXktYm9vdC1pbWFnZS5pbWc8L2Rvd25sb2FkLXVyaT4KICAg\
ICAgPGltYWdlLXZlcmlmaWNhdGlvbj4KICAgICAgICA8aGFzaC1hbGdvcml0aG0+aWV0Zi1zenRwLWNvbnZleWVkLWluZm86c2hhLTI1Njw\
vaGFzaC1hbGdvcml0aG0+CiAgICAgICAgPGhhc2gtdmFsdWU+NmY6ODc6MGI6YWY6M2M6M2E6ZmU6MDM6MTQ6NTc6MjQ6Mjc6YzY6YmE6ND\
k6MDQ6Yjk6NTI6OTQ6NDM6OGQ6Yjg6N2I6MjE6YjM6YTk6MjQ6OTI6MzE6MmM6MDA6ZDk8L2hhc2gtdmFsdWU+CiAgICAgIDwvaW1hZ2Utd\
mVyaWZpY2F0aW9uPgogICAgPC9ib290LWltYWdlPgogICAgPHByZS1jb25maWd1cmF0aW9uLXNjcmlwdD5JeTlpYVc0dlltRnphQXBsWTJo\
dklDSnBibk5wWkdVZ2RHaGxJSEJ5WlMxamIyNW1hV2QxY21GMGFXOXVMWE5qY21sd2RDNHVMaUlLPC9wcmUtY29uZmlndXJhdGlvbi1zY3J\
pcHQ+CiAgICA8Y29uZmlndXJhdGlvbi1oYW5kbGluZz5tZXJnZTwvY29uZmlndXJhdGlvbi1oYW5kbGluZz4KICAgIDxjb25maWd1cmF0aW\
9uPlBIUnZjQ0I0Yld4dWN6MGlhSFIwY0hNNkwyVjRZVzF3YkdVdVkyOXRMMk52Ym1acFp5SStDaUFnUEdGdWVTMTRiV3d0WTI5dWRHVnVkQ\
zF2YTJGNUx6NEtQQzkwYjNBK0NnPT08L2NvbmZpZ3VyYXRpb24+CiAgICA8cG9zdC1jb25maWd1cmF0aW9uLXNjcmlwdD5JeTlpYVc0dllt\
RnphQXBsWTJodklDSnBibk5wWkdVZ2RHaGxJSEJ2YzNRdFkyOXVabWxuZFhKaGRHbHZiaTF6WTNKcGNIUXVMaTRpQ2c9PTwvcG9zdC1jb25\
maWd1cmF0aW9uLXNjcmlwdD4KICA8L29uYm9hcmRpbmctaW5mb3JtYXRpb24+CjwvY29udGVudC1kYXRhPgo=</conveyed-information>
</output>
Request:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.json
{
"ietf-sztp-bootstrap-server:input" : {
"hw-model" : "model-x",
"os-name" : "vendor-os",
"os-version" : "17.3R2.1",
"nonce" : "BASE64VALUE="
}
}
EOM
# POST 'input' for the "get-bootstrapping-data" RPC resource
curl -i -X POST --data @input.json -H "Content-Type:application/yang-data+json" --cacert sbi_trust_chain.pe\
m --key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-num\
ber:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:get-bootstrapping-data \
1> output/post_rpc_input.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_rpc_input.out
# cleanup
rm -f input.json
Response:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 200 OK
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 1187
Date: Fri, 15 Jan 2021 02:38:10 GMT
Server: <redacted>
{
"ietf-sztp-bootstrap-server:output": {
"conveyed-information": "MIIDOQYLKoZIhvcNAQkQASugggMoBIIDJHsKICAiaWV0Zi1zenRwLWNvbnZleWVkLWluZm86b25ib2\
FyZGluZy1pbmZvcm1hdGlvbiI6IHsKICAgICJib290LWltYWdlIjogewogICAgICAiZG93bmxvYWQtdXJpIjogWwogICAgICAgICJodHRwc\
zovL2V4YW1wbGUuY29tL215LWJvb3QtaW1hZ2UuaW1nIgogICAgICBdLAogICAgICAiaW1hZ2UtdmVyaWZpY2F0aW9uIjogWwogICAgICAg\
IHsKICAgICAgICAgICJoYXNoLWFsZ29yaXRobSI6ICJpZXRmLXN6dHAtY29udmV5ZWQtaW5mbzpzaGEtMjU2IiwKICAgICAgICAgICJoYXN\
oLXZhbHVlIjogIjZmOjg3OjBiOmFmOjNjOjNhOmZlOjAzOjE0OjU3OjI0OjI3OmM2OmJhOjQ5OjA0OmI5OjUyOjk0OjQzOjhkOmI4OjdiOj\
IxOmIzOmE5OjI0OjkyOjMxOjJjOjAwOmQ5IgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJwcmUtY29uZmlndXJhdGlvbi1zY3Jpc\
HQiOiAiSXk5aWFXNHZZbUZ6YUFwbFkyaHZJQ0pwYm5OcFpHVWdkR2hsSUhCeVpTMWpiMjVtYVdkMWNtRjBhVzl1TFhOamNtbHdkQzR1TGlJ\
SyIsCiAgICAiY29uZmlndXJhdGlvbi1oYW5kbGluZyI6ICJtZXJnZSIsCiAgICAiY29uZmlndXJhdGlvbiI6ICJQSFJ2Y0NCNGJXeHVjejB\
pYUhSMGNITTZMMlY0WVcxd2JHVXVZMjl0TDJOdmJtWnBaeUkrQ2lBZ1BHRnVlUzE0Yld3dFkyOXVkR1Z1ZEMxdmEyRjVMejRLUEM5MGIzQS\
tDZz09IiwKICAgICJwb3N0LWNvbmZpZ3VyYXRpb24tc2NyaXB0IjogIkl5OWlhVzR2WW1GemFBcGxZMmh2SUNKcGJuTnBaR1VnZEdobElIQ\
nZjM1F0WTI5dVptbG5kWEpoZEdsdmJpMXpZM0pwY0hRdUxpNGlDZz09IgogIH0KfQ=="
}
}
Request:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.xml
<input xmlns="urn:ietf:params:xml:ns:yang:ietf-sztp-bootstrap-server">
<progress-type>bootstrap-complete</progress-type>
<message>example message</message>
<ssh-host-keys>
<ssh-host-key>
<algorithm>ssh-rsa</algorithm>
<key-data>BASE64VALUE=</key-data>
</ssh-host-key>
<ssh-host-key>
<algorithm>rsa-sha2-256</algorithm>
<key-data>BASE64VALUE=</key-data>
</ssh-host-key>
</ssh-host-keys>
<trust-anchor-certs>
<trust-anchor-cert>BASE64VALUE=</trust-anchor-cert>
</trust-anchor-certs>
</input>
EOM
# POST it to the "report-progress" RPC resource
curl -i -X POST --data @input.xml -H "Content-Type:application/yang-data+xml" --cacert sbi_trust_chain.pem \
--key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-numbe\
r:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:report-progress 1> output\
/post_progress_report_xml.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_progress_report_xml.out
# cleanup
rm -f input.xml
Response:
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:12 GMT
Server: <redacted>
Request:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > bootstrap-complete.json
{
"ietf-sztp-bootstrap-server:input" : {
"progress-type" : "bootstrap-complete",
"message" : "Dynamically generated SSH host key included.",
"ssh-host-keys" : {
"ssh-host-key" : [
{
"algorithm" : "ssh-rsa",
"key-data" : "BASE64VALUE="
}
]
}
}
}
EOM
# POST it to the "report-progress" RPC resource
curl -i -X POST --data @bootstrap-complete.json -H "Content-Type:application/yang-data+json" --cacert sbi_t\
rust_chain.pem --key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user \
my-serial-number:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:report-pro\
gress 1> output/post_progress_report.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_progress_report.out
# cleanup
rm -f bootstrap-complete.json
Response:
HTTP/1.1 204 No Content
Content-Type: application/octet-stream
Date: Fri, 15 Jan 2021 02:38:11 GMT
Server: <redacted>
Errors (e.g., HTTP status code 4XX) are also returned using the desired encoding.
Request:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.xml
<input xmlns="urn:ietf:params:xml:ns:yang:ietf-sztp-bootstrap-server">
<foo-bar>bootstrap-initiated</foo-bar>
</input>
EOM
# POST it to the "report-progress" RPC resource
curl -i -X POST --data @input.xml -H "Content-Type:application/yang-data+xml" --cacert sbi_trust_chain.pem \
--key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-numbe\
r:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:report-progress 1> output\
/post_progress_report_error_xml.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_progress_report_error_xml.out
# cleanup
rm -f input.xml
Response:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 400 Bad Request
Content-Type: application/yang-data+xml; charset=utf-8
Content-Length: 417
Date: Fri, 15 Jan 2021 02:38:12 GMT
Server: <redacted>
<?xml version="1.0" ?>
<content-data xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
<errors xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
<error>
<error-type>protocol</error-type>
<error-tag>malformed-message</error-tag>
<error-message>Unable to parse "input" document: Doesn't match schema: /input/foo-bar</erro\
r-message>
</error>
</errors>
</content-data>
Request:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
#!/bin/sh
# initialize the 'input' node for the RPC
cat << EOM > input.json
{
"ietf-sztp-bootstrap-server:input" : {
"foo-bar" : "bootstrap-initiated"
}
}
EOM
# POST it to the "report-progress" RPC resource
curl -i -X POST --data @input.json -H "Content-Type:application/yang-data+json" --cacert sbi_trust_chain.pe\
m --key pki/client/end-entity/private_key.pem --cert pki/client/end-entity/my_cert.pem --user my-serial-num\
ber:my-secret https://127.0.0.1:9090/restconf/operations/ietf-sztp-bootstrap-server:report-progress 1> outp\
ut/post_progress_report_error.out 2>/dev/null
# line-return needed for markdown
echo "" 1>> output/post_progress_report_error.out
# cleanup
rm -f input.json
Response:
=================================== NOTE: '\' line wrapping per RFC 8792 ===================================
HTTP/1.1 400 Bad Request
Content-Type: application/yang-data+json; charset=utf-8
Content-Length: 275
Date: Fri, 15 Jan 2021 02:38:12 GMT
Server: <redacted>
{
"ietf-restconf:errors": {
"error": [
{
"error-type": "protocol",
"error-tag": "malformed-message",
"error-message": "Unable to parse \"input\" document: Doesn't match schema: /ietf-sztp-bootstrap-se\
rver:input/foo-bar"
}
]
}
}
SZTPD uses an “eastbound” interface to interact with peering systems.
This information is mostly interesting to those wanting to standup a peering-system for SZTPD to interact with.
In order to enable external TLS terminators to convey the client certificate passed during the TLS handshake, SZTPD looks for the “X-Client-Cert” header field. Also discussed in Section 2.3.1.2 (HTTP vs HTTP) of SZPTD Installation Guide.
SZTPD may be configured to reach out to an external RDBMS server for its database. The protocol used for this connection is database-specific, and may be shroudable by a TLS session (recommended).
Dynamic callouts may be configured to reach out to external systems to either push information to or fetch information from them.
Dynamic callouts are currently only implemented via plugins (see Plugins) loaded into SZTPD, enabling the plugin to implement a protocol of its choosing, but it is planned to also enable to SZTPD to also execute via RESTCONF (i.e., an HTTP “POST” request).
In either case, dyanmic callouts are modeled using YANG ‘rpc’ statements.
When executed via a plugin, the Python function takes two parameters. The first parameter is ‘input’, a Python object having a structure matching the ‘rpc’ statement’s ‘input’ node. The second parameter is ‘opaque’, a Python object having an arbitrary (‘anydata’, in YANG parlance) structure configured for the specific ‘dynamic-callout’.
The following “rpc” statement is defined in the “wn-app-rpcs” YANG module:
rpcs
+-- rpc relay-notification
The following “rpc” statements are defined in the “wn-sztpd-rpcs” YANG module:
rpcs
+-- rpc relay-progress-report
+-- rpc verify-device-ownership
+-- rpc get-conveyed-information
Please see Glossary of Dynamic Callouts for more information about the various dynamic callouts.
Following lists all of the dynamic callouts implemented by SZTPD (see Dynamic Callouts).
A dynamic callout implementing the “relay-notification” RPC is used to send notifications, as defined by the various YANG modules implemented by SZTPD. Notifications are those defined by the YANG “notification” statement. All of the notifications are presented in the Glossary of Notifications section.
rpcs:
+---x relay-notification {relay-notification}?
+---- input
+---w notification? anydata
Following is what an HTTP request sent from SZTPD might look like:
REQUEST
POST /restconf/operations/wn-app-rpcs:relay-notification HTTP/1.1
HOST: example.com
Content-Type: application/yang-data+json
{
"wn-app-rpcs:input" : {
"notification": {
"eventTime": "2019-03-22T12:35:00Z",
"wn-sztpd-1:unused-device-record-lingering": {
"device-record": "fault",
"created": "2019-01-22T10:32:12Z",
"num-times-modified": 3,
"last-modified": "2019-03-20T09:51:44Z"
}
}
}
}
Following is an example HTTP response sent from the remote endpoint:
RESPONSE
HTTP/1.1 204 OK
Date: Sat, 31 Oct 2015 17:02:40 GMT
Server: example-server
Content-Type: application/yang-data+json
To configure SZTPD to relay notifications, the “relay-notification-callout” node under the host-level and/or tenant-level5 “preferences” container must point to a “dynamic-callout” having the “rpc-supported” value “relay-notification”.
A dynamic callout implementing the “relay-progress-report” RPC is used to send progress-reports, as defined by the various YANG modules implemented by SZTPD. Notifications are those defined by the YANG “progress-report” statement. All of the progress-reports are presented in the [Notifications] section.
The tree diagram for the “relay-progress-report” RPC follows:
rpcs:
+---x relay-progress-report {relay-progress-report}?
+---- input
+---w serial-number string
+---w source-ip-address ietf-inet-types:ip-address
+---w identity-certificate? ietf-crypto-types:cms
+---w from-device? anydata
Following is what an HTTP request sent from SZTPD might look like:
REQUEST
POST /restconf/operations/wn-sztpd-rpcs:get-conveyed-information HTTP/1.1
HOST: example.com
Content-Type: application/yang-data+json
{
"wn-sztpd-rpcs:input" : {
"serial-number": "my-serial-number",
"source-ip-address": "10.20.30.40",
"identity-certificate": "BASE64VALUE=",
"from-device": {
"ietf-sztp-bootstrap-server:input" : {
"progress-type": "bootstrap-complete",
"message": "example message",
"ssh-host-keys": {
"ssh-host-key": [
{
"algorithm": "ssh-rsa",
"key-data": "BASE64VALUE="
},
{
"algorithm": "rsa-sha2-256",
"key-data": "BASE64VALUE="
}
]
},
"trust-anchor-certs": {
"trust-anchor-cert": [ "BASE64VALUE=" ]
}
}
}
}
}
Following is an example HTTP response sent from the remote endpoint:
RESPONSE
HTTP/1.1 204 OK
Date: Sat, 31 Oct 2015 17:02:40 GMT
Server: example-server
Content-Type: application/yang-data+json
To configure SZTPD to relay progress reports, the “relay-progress-report-callout” node under the host-level and/or tenant-level6 “preferences” container must point to a “dynamic-callout” having the “rpc-supported” value “relay-progress-report”.
A dynamic callout implementing the “verify-device-ownership” RPC is used to verify that devices (serial numbers) to the configured authority (i.e., a specific tenant). The RPC’s tree diagram follows:
The tree diagram for the “verify-device-ownership” RPC follows:
rpcs:
+---x verify-device-ownership {verify-device-ownership}?
+---- input
| +---w tenant string
| +---w serial-number* string
+---- output
+--ro verification-results
+--ro verification-result* [serial-number]
+--ro serial-number string
+--ro result enumeration
Following is what an HTTP request sent from SZTPD might look like:
REQUEST
POST /restconf/operations/wn-sztpd-rpcs:verify-device-ownership HTTP/1.1
HOST: example.com
Content-Type: application/yang-data+json
{
"wn-sztpd-rpcs:input" : {
"tenant": "not-applicable",
"serial-number": [ "sn-111", "sn-222", "sn-333" ]
}
}
Following is an example HTTP response sent from the remote endpoint:
RESPONSE
HTTP/1.1 200 OK
Date: Sat, 31 Oct 2015 17:02:40 GMT
Server: example-server
Content-Type: application/yang-data+json
{
"ietf-sztpd-rpcs:output" : {
"verification-results": {
"verification-result": [
{
"serial-number": "sn-111",
"result": "success"
},
{
"serial-number": "sn-222",
"result": "failure"
},
{
"serial-number": "sn-333",
"result": "success"
}
]
}
}
}
To configure SZTPD to verify device ownership, the “ownership-authorization” node under the host-level “device-types” must point to a “dynamic-callout” having the “rpc-supported” value “verify-device-ownership”.
A dynamic callout implementing the “get-conveyed-information” RPC, used to fetch a just-in-time generated response to a bootstrapping device. The RPC’s tree diagram follows:
The tree diagram for the “get-conveyed-information” RPC follows:
rpcs:
+---x get-conveyed-information {get-conveyed-information}?
+---- input
| +---w serial-number string
| +---w source-ip-address ietf-inet-types:ip-address
| +---w identity-certificate? ietf-crypto-types:cms
| +---w from-device? anydata
+---- output
+--ro conveyed-information anydata
Following is what an HTTP request sent from SZTPD might look like:
REQUEST
POST /restconf/operations/wn-sztpd-rpcs:get-conveyed-information HTTP/1.1
HOST: example.com
Content-Type: application/yang-data+json
{
"wn-sztpd-rpcs:input" : {
"serial-number": "my-serial-number",
"source-ip-address": "10.20.30.40",
"identity-certificate": "BASE64VALUE=",
"from-device": {
"ietf-sztp-bootstrap-server:input" : {
"hw-model": "model-x",
"os-name": "vendor-os",
"os-version": "17.3R2.1",
"nonce": "BASE64VALUE=",
"ietf-sztp-csr:csr": {
"p10": "BASE64VALUE="
}
}
}
}
}
Following is an example HTTP response sent from the remote endpoint:
RESPONSE
HTTP/1.1 200 OK
Date: Sat, 31 Oct 2015 17:02:40 GMT
Server: example-server
Content-Type: application/yang-data+json
{
"ietf-sztpd-rpcs:output" : {
"conveyed-information": "BASE64VALUE="
}
}
To configure SZTPD to dynamically obtain conveyed-information from an external system, a device’s “response-manager” configuration must have a “matched-response” of type “conveyed-information” with a “dynamic-callout” having the “rpc-supported” value “get-conveyed-information”.
These are the notifications that may be sent via the “relay-notification” dynamic callout (see The “relay-notification” Dynamic Callout).
The following “notification” statements are defined in the “wn-app” YANG module:
notifications
+-- unreferenced-node-lingering
+-- unreferenced-node-purged
+-- admin-account-activation-expired
+-- admin-account-password-aging
+-- admin-account-disabled
+-- admin-account-purged
+-- audit-log-entry-purged
The following “notification” statements are defined in the “wn-sztpd-0” YANG module, which is used as a basis for all the SZTPD YANG modules (mode ‘1’ and mode ‘x’ models):
notifications
+-- voucher-expiration
+-- unused-device-record-lingering
+-- unused-device-record-purged
+-- used-device-record-lingering
+-- used-device-record-purged
+-- progress-report-received
The following “notification” statement is defined in the “ietf-crypto-types” YANG module:
notifications
+-- certificate-expiration
The following “notification” statements are defined in the “ietf-yang-library” YANG module:
notifications
+-- yang-library-update
+-- yang-library-change
The tree-diagram for this notification is as follows:
+---n unreferenced-node-lingering {wn-app:storage-reclamation-implemented}?
+--ro last-referenced union
The tree-diagram for this notification is as follows:
+---n unreferenced-node-purged {wn-app:storage-reclamation-implemented}?
+--ro last-referenced union
The tree-diagram for this notification is as follows:
+---n admin-account-activation-expired {wn-app:account-activation-expiration-implemented}?
The tree-diagram for this notification is as follows:
+---n admin-account-password-aging {wn-app:password-aging-implemented}?
+--ro expiration-date ietf-yang-types:date-and-time
The tree-diagram for this notification is as follows:
+---n admin-account-disabled {wn-app:storage-reclamation-implemented}?
The tree-diagram for this notification is as follows:
+---n admin-account-purged {wn-app:storage-reclamation-implemented}?
The tree-diagram for this notification is as follows:
+---n voucher-expiration
+--ro expiration-date ietf-yang-types:date-and-time
The tree-diagram for this notification is as follows:
+---n unused-device-record-lingering {wn-app:storage-reclamation-implemented}?
+--ro nbi-access-stats
+--ro created ietf-yang-types:date-and-time
+--ro num-times-modified uint16
+--ro last-modified ietf-yang-types:date-and-time
The tree-diagram for this notification is as follows:
+---n unused-device-record-purged {wn-app:storage-reclamation-implemented}?
+--ro nbi-access-stats
+--ro created ietf-yang-types:date-and-time
+--ro num-times-modified uint16
+--ro last-modified ietf-yang-types:date-and-time
The tree-diagram for this notification is as follows:
+---n used-device-record-lingering {wn-app:storage-reclamation-implemented}?
+--ro nbi-access-stats
| +--ro created ietf-yang-types:date-and-time
| +--ro num-times-modified uint16
| +--ro last-modified ietf-yang-types:date-and-time
+--ro sbi-access-stats
+--ro num-times-accessed uint16
+--ro first-accessed ietf-yang-types:date-and-time
+--ro last-accessed ietf-yang-types:date-and-time
The tree-diagram for this notification is as follows:
+---n used-device-record-purged {wn-app:storage-reclamation-implemented}?
+--ro nbi-access-stats
| +--ro created ietf-yang-types:date-and-time
| +--ro num-times-modified uint16
| +--ro last-modified ietf-yang-types:date-and-time
+--ro sbi-access-stats
+--ro num-times-accessed uint16
+--ro first-accessed ietf-yang-types:date-and-time
+--ro last-accessed ietf-yang-types:date-and-time
The tree-diagram for this notification is as follows:
+---n certificate-expiration {ietf-crypto-types:certificate-expiration-notification}?
+--ro expiration-date ietf-yang-types:date-and-time
The tree-diagram for this notification is as follows:
x---n yang-library-change
x--ro module-set-id -> /ietf-yang-library:modules-state/ietf-yang-library:module-set-id
The tree-diagram for this notification is as follows:
+---n yang-library-update
+--ro content-id -> /ietf-yang-library:yang-library/ietf-yang-library:content-id
The tree-diagram for this notification is as follows:
x---n yang-library-change
x--ro module-set-id -> /ietf-yang-library:modules-state/ietf-yang-library:module-set-id
A simulator has been developed, primarily to aid in the development of the RFC 8572 compliant bootstrapping agent, though inspection of its source code is helpful towards understand how to use SZTPD’s Northbound Interface (e.g., its use of the curl
command line utility).
The simulator (i.e., the script run-sztpd-test.sh
) performs the following steps:
Start and initialize three SZTPD servers for the following roles:
Instance | Purpose |
---|---|
1 | A trusted bootstrap server to redirect the device to instance #2. |
2 | An initially untrusted bootstrap server to redirect the device to instance #3. |
3 | An initially untrusted bootstrap server to give the device its onboarding data. |
Each SZTP server is an instance of the sztpd
process.
Start an instance of a demo RFC 8572 agent (the rfc8572-simulator.sh
script).
Parameters are passed into the agent providing necessary values (e.g., the “serial-number” value).
Wait for the agent to complete and then shutdown the three SZTPD instances.
No trace on the filesystem is retained as:
run-sztpd-test.sh
and rfc8572-simulator.sh
scripts cleans up after themselves.sztpd
processes are run using the “in-memory” database7.Successful execution of the requires a few packages to be installed.
curl
utility, many times installed by OS)When posted, the simulator can be downloaded here: https://watsen.net/support.
Unarchive the TGZ in a local directory, for example:
$ tar -xzvf ./sztpd-simulator-0.0.8.tgz
// This command creates a directory called "sztpd-simulator".
Inside the “sztpd-simulator” directory are a number of files and directories:
Resource | Purpose |
---|---|
run-simulator.sh | The script that starts 3 SZTPD servers and an RFC 8572 agent. |
rfc8572-agent.sh | A simple curl based agent that simulates an RFC 8572 agent. |
templates/ | A directory containing config used to init the SZTP instances. |
pki/ | A directory containing code to initialize the PKI for the demo. |
xrd/ | A directory containing files to validates the “host-meta” XRD. |
There is little need to customize the simulator scripts before running.
The most likely customization is to adjust the “PYTHON” and “PIP” variables, located at the top of the “run-simulator.sh” and “rfc8572-agent.sh” files. For instance, if Python is installed as “python3.8”, then the values should be set as follows:
PYTHON=python3.8
PIP=pip3.8
Another possible customization is to adjust the ports that the various sztpd
instances will open, for instance, to deconflict from a port already in use. To adjust the ports used, edit the top of the “run-sztpd-test.sh” and modify the various “PORT” values listed at the top of that file.
The simulator creates a distinct PKI for each endpoint. As each SZTPD instance (in this demo) has two endpoints (an NBI and and SBI) and there are three SZTPD instances, a total of six certificate chains are created. Each certificate chain contains four certificates (a root certificate, two intermediate certificates, and an end-entity certificate), thus a total of Twenty-four certificates are created in total.
Whilst the certificates could be dynamically generated for each execution of the simulator, for multiple executions, having the PKI created already saves time.
Assuming the current directory is the “sztpd-simulator” directory, the following commands:
$ cd pki
$ make pki
$ cd ..
If ever needed, make clean
can be used to return the directory hierarchy to its original form.
Assuming the current directory is the “sztpd-simulator” directory, the following command will run the simulator:
$ ./run-sztpd-test.sh
Each time the simulator runs, it first tests if the PKI has been initialized. If the PKI has not been initialized, the simulator exits with the message:
PKI needs to be initialized first.
- e.g., `cd pki; make pki; cd ..;`
Otherwise the simulator runs without any other prompts, producing output such as:
Creating instances...
^-- Creating SZTPD instance 1...okay. (SZTPD instance 1 running with PID 22089)
^-- Creating SZTPD instance 2...okay. (SZTPD instance 2 running with PID 220155)
^-- Creating SZTPD instance 3...okay. (SZTPD instance 3 running with PID 22091)
Giving servers a couple seconds to startup...
Configuring instances...
^-- Configuring SZTPD instance 1...
^-- Configuring SZTPD instance 2...
^-- Configuring SZTPD instance 3...
Giving servers a couple seconds to open their ports...
Testing instances...
^-- Testing SZTPD instance 1
^-- Testing SZTPD instance 2
^-- Testing SZTPD instance 3
Running simulator...
^-- Getting bootstrapping data...
^-- Processing bootstrapping data...
^-- Processing redirect information...
^-- Getting bootstrapping data from next server...
^-- Processing bootstrapping data...
^-- Processing redirect information...
^-- Getting bootstrapping data from next server...
^-- Processing bootstrapping data...
^-- Processing onboarding information...
^-- Bootstrap complete.
Killing `sztpd` instances...
^-- Sending SIGTERM to instance 1 (PID 22089)
^-- Sending SIGTERM to instance 2 (PID 22090)
^-- Sending SIGTERM to instance 3 (PID 22091)
Giving servers a couple seconds to shutdown...
Verifying instances are killed...
^-- Verifying SZTPD instance 1 killed...okay.
^-- Verifying SZTPD instance 2 killed...okay.
^-- Verifying SZTPD instance 3 killed...okay.
All done!
The simulator makes effort to clean up after itself. For instance, all files are created in a temporary directory. However, currently, if the simulator experiences an unexpected error, it may exit without first shutting down the sztpd
instances.
If the sztpd
instances are not removed, they can be removed manually. For instance:
$ ps | grep sztpd
23816 ttys024 0:02.01 python sztpd sqlite:///:memory:
23817 ttys024 0:02.01 python sztpd sqlite:///:memory:
23818 ttys024 0:02.01 python sztpd sqlite:///:memory:
$ kill 23816
$ kill 23817
$ kill 23818
This step entails file-system level access to the SZTP server.↩︎
Ensure that you run the command using the same version of Python and/or Python virtual environment that SZTPD uses.↩︎
In a multi-tenant deployment, only host-level administrators have access to this configuration; tenants can only use plugins that have been configured by host-level administrators.↩︎
The “BASE64VALUE=” values are not real; they are used in this example only for readability.↩︎
In a multi-tenant mode, when the notification is tenantspecific, SZTPD will only use the tenant-level dynamic callout, if configured.↩︎
In a multi-tenant mode, when the progress report comes from a tenant’s device, SZTPD will only use the tenant-level dynamic callout, if configured.↩︎
For information about the in-memory database, please See the “In-memory Database” section in the Installation Guide.↩︎