#
Data Security Models
UniConfig supports encryption and hashing of leaf/leaf-list values on SSH and RESTCONF API. Following sections describe supported security models in depth.
#
Data encryption
UniConfig uses asymmetric encryption for ensuring confidentiality of selected leaf and leaf-list values. Currently, only RSA ciphers are supported (both global UniConfig and device-level key-pairs). Encryption is supported in 'uniconfig', 'unistore', and 'templates' topologies.
#
Global-device encryption architecture
Both UniConfig and device uses PKI for encryption of data:
- UniConfig side: All selected leaves are encrypted using global public key when this data enters UniConfig via RESTCONF API or UniConfig SSH shell API. Afterwards, data is stored in database in the encrypted format. UniConfig has also access to private key which is used internally for decryption of already encrypted data.
- Device side: Device exposes public key and UniConfig uses this key for re-encryption of data before it is sent to device ('commit'/'checked-commit' operations). However, device doesn't expose its private key - UniConfig is not able to detect changes done to encrypted data (updated leaves/leaf-lists) - it is only able to detect, if data was removed or created, not updated. Because of this reason, UniConfig assumes that read encrypted data from device has been encrypted using the same public key as it was used by UniConfig.
Following picture depicts data transformations done on UniConfig interfaces:
#
Global-only encryption architecture
In comparison to Global-device encryption architecture this model uses only global key-pair for encryption of data. Devices contain only plaintext data.
- Public key is used for encryption of received data via RESTCONF, UniConfig shell API, and when syncing configuration from device to UniConfig transaction ('sync-from-network' operation).
- Private key is used for decryption of encrypted data before forwarding this configuration to device ('commit'/'checked-commit' operations).
Next picture depicts data transformations done on UniConfig interfaces:
Reading of operational data from device directly (GET under 'yang-ext:mount') shows data in unencrypted format. Application gateways should restrict access to mountpoints in this use-case.
#
YANG support
Leaves and leaf-lists, which value user would like to store encrypted, must be marked using YANG extension without any parameters. Currently, only leaves with 'string' type (direct/indirect with custom type definitions) are supported, since encrypted values are base64 encoded. Also, be aware that type constraints must accept encrypted values.
Example YANG module that defines one 'encrypt' extension:
module frinx-encrypt {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:frinx-encrypt;
prefix frinx-encrypt;
revision 2021-12-15 {
description "Initial revision";
}
extension encrypt {
}
}
Usage of the extension in the 'config' module:
module config {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:config;
prefix config;
import frinx-encrypt {
prefix fe;
revision-date 2021-12-15;
}
revision 2021-12-15 {
description "Initial revision";
}
typedef secret-string {
type string;
}
container config {
list properties {
key property-id;
leaf property-id {
type string;
}
leaf enabled {
type boolean;
}
leaf value {
type string;
fe:encrypt;
}
}
container routing {
container eigrp {
leaf process-id {
type uint16;
}
leaf password {
type secret-string;
fe:encrypt;
}
}
leaf-list neighbor-key {
type leafref {
path "../../properties/value";
}
fe:encrypt;
}
}
}
}
Many times, it is not possible to modify existing YANG files because they are already deployed on device, for example device running with NETCONF server. In this case, user can still mark what leaves should be encrypted using additional YANG module that contains deviations.
Example:
module encrypted-paths {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:encrypted-paths;
prefix ep;
import snmp {
prefix snmp;
revision-date 2019-11-10;
}
import frinx-encrypt {
prefix fe;
revision-date 2021-12-15;
}
revision 2019-11-10 {
description "Initial revision";
}
deviation "/snmp:snmp/snmp:usm/snmp:remote/snmp:user/snmp:auth/snmp:protocol/snmp:md5/snmp:md5/snmp:key-type/snmp:password/snmp:password" {
deviate add {
fe:encrypt;
}
}
deviation "/snmp:snmp/snmp:usm/snmp:remote/snmp:user/snmp:auth/snmp:protocol/snmp:md5/snmp:md5/snmp:key-type/snmp:key/snmp:key" {
deviate add {
fe:encrypt;
}
}
deviation "/snmp:snmp/snmp:usm/snmp:remote/snmp:user/snmp:auth/snmp:protocol/snmp:sha/snmp:sha/snmp:key-type/snmp:password/snmp:password" {
deviate add {
fe:encrypt;
}
}
deviation "/snmp:snmp/snmp:usm/snmp:remote/snmp:user/snmp:auth/snmp:protocol/snmp:sha/snmp:sha/snmp:key-type/snmp:key/snmp:key" {
deviate add {
fe:encrypt;
}
}
}
Afterwards, user has 2 options how this module can be coupled with modules from device (NETCONF):
- Explicit specification of this side-loaded module in the 'install-node' request - using 'netconf-node-topology:yang-module-capabilities' settings (see 'Device installation' section).
- Automatic detection of side-loaded module - UniConfig looks for specific capability from NETCONF server, inherits its revision, and then looks for side-loaded module with specific name and inherited revision (see 'Configuration' section). This option is preferred, if deployment contains multiple versions of devices and list of encrypted paths are different on each version.
#
Configuration
Global RSA key-pair is stored inside PEM-encoded files in the 'rsa' directory under UniConfig root. Name of the private key must be 'encrypt_key' and name of the public key must be 'encrypt_key.pub'. If user doesn't provide these files, UniConfig will automatically generate its own key-pair with length of 2048 bits. All UniConfig instances in the cluster must use the same key-pair.
Encryption settings are stored in the 'config/lighty-uniconfig-config.json' file under 'crypto' root object.
Example:
crypto.encrypt-enabled=true
crypto.encrypt-extension-id=frinx-encrypt:encrypt
crypto.netconf-reference-module-name=system
crypto.netconf-encrypted-paths-module-name=encrypted-paths
- encrypt-enabled - If this setting is false, then encryption is disabled despite other settings or install-node parameters. If this setting is true, then encryption is enabled. The default value is true.
- encrypt-extension-id - If this setting is not defined, then encryption is disabled despite other settings or install-node parameters. The value must have the format [module-name]:[extension-name] and specifies extension used for marking of encrypted leaves/leaf-lists in YANG modules. Corresponding YANG module, that contain this extension, can be part of device/unistore YANG schemas, or it can be side-loaded during installation of NETCONF device as imported module from 'default' repository.
- netconf-reference-module - Name of the module for which NETCONF client looks for during mounting process. If UniConfig finds module with this name in the list of received capabilities, then it uses its revision in the lookup process for correct YANG module with encrypted paths (using deviations).
- netconf-encrypted-paths-module-name - Name of the module which contains deviations with paths to encrypted leaves/leaf-lists. There could be multiple revisions of this file prepared in the 'default' NETCONF repository. NETCONF client in the UniConfig chooses the correct revision based on 'netconf-reference-module-name' setting. Together, netconf-reference-module-name' and 'netconf-encrypted-paths-module-name' can be used for autoload of encrypted paths for different versions of devices.
If 'default' YANG repository contains module with encrypted-paths without defined YANG revision and device does not already provide encryption capability, then encrypted-paths module is used as the last resort during installation of device ('netconfReferenceModuleName' and matching of revisions are ignored).
#
Change encryption status
For proper working of this RPC it is necessary to enable notifications with this parameter:
notifications.enabled=true
- Encryption can be enabled or disabled with the parameter:
crypto.encrypt-enabled=true
- The value of this parameter can be changed with the 'change-encryption-status' RPC request.
Following request is used to enable encryption:
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/crypto:change-encryption-status' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
"input": {
"encryption-enabled": true
}
}'
After calling this command, all Uniconfig instances will set this parameter using the notification service to the value which is sent via RPC, in this case it will be set to value true.
Following request is used to disable encryption:
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/crypto:change-encryption-status' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
"input": {
"encryption-enabled": false
}
}'
To check the functionality of this RPC, after calling install-device RPC we can request the password of the node, which when encryption is enabled will be returned encrypted, and when it is disabled password will be plain text.
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=dev01/netconf-node-topology:password' \
--header 'Accept: application/json'
{
"netconf-node-topology:password": "rsa_gFXLXIxbeA9Vt8p0+JlprK1YUznBjk9DHRVlZ6Bm2nP0Fi/jUjsAUsGU814QyAZhXBiK6MY7ul75bE1EEI4uj0PlWT4xFYTXaKaMwgdHSCOnE/I6CGakuzGVGgzztKcSA/AsP8/bgXO0Rellw/S6z9U6h8blIG4Ff73GJOr53slWqoqMvAaXgSQtSbYB0EsPey1YqcukKuZnufJAazbHNHuxU1TFxcN/Cn1vTUEr8IATCAohfO7k5MOn0Ds/gYKt63RBO6000gcSP5PS9LRWhucSdLYc4b2+3soz0VXUCGEMPNSrmDXyWKUftI1S3qLfHthHoGEN1YXKGll5ccxW9g=="
}
#
Device installation
There are 2 settings related to encryption in the 'install-node' RPC request:
- uniconfig-config:crypto - It allows specifying path to public key on device - 'public-key-path' (leaf with RFC-8040 path) and cipher type (by default, RSA is used) - 'public-key-cipher-type'. If path to public key is specified, and it exists on device, then Global-device encryption model is used. Otherwise, Global-only encryption model is selected.
- netconf-node-topology:yang-module-capabilities - If autoload of YANG module with encrypted paths is not used and device itself doesn't specify encrypted leaves, then it is necessary to side-load YANG module with encrypted paths. This parameter is relevant only on NETCONF nodes. Side-loaded modules must be expressed in the format of NETCONF capabilities.
Following request shows install-node request with specified both path to public key and side-loaded YANG module 'encrypted-paths' with revision '2021-12-15' and namespace 'urn:ietf:params:xml:ns:yang:encrypted-paths'.
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/connection-manager:install-node' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
"input": {
"node-id": "dev01",
"netconf": {
"netconf-node-topology:host": "10.103.5.47",
"netconf-node-topology:port": 2022,
"netconf-node-topology:keepalive-delay": 5,
"netconf-node-topology:max-connection-attempts": 1,
"netconf-node-topology:connection-timeout-millis": 60000,
"netconf-node-topology:default-request-timeout-millis": 60000,
"netconf-node-topology:tcp-only": false,
"netconf-node-topology:username": "admin",
"netconf-node-topology:password": "admin",
"netconf-node-topology:sleep-factor": 1.0,
"uniconfig-config:uniconfig-native-enabled": true,
"netconf-node-topology:edit-config-test-option": "set",
"uniconfig-config:crypto": {
"public-key-path": "/crypto/pki/config-keys=config_key/pub-key",
"public-key-cipher-type": "RSA"
},
"netconf-node-topology:yang-module-capabilities": {
"capability": [
"urn:ietf:params:xml:ns:yang:encrypted-paths?module=encrypted-paths&revision=2021-12-15"
]
}
}
}
}'
During installation, UniConfig tries to download public key from device. Public key can be verified using GET request:
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=dev01/crypto:crypto?content=nonconfig' \
--header 'Accept: application/json'
{
"crypto": {
"encryption-public-key": "MIIBIjANBgkqhkiG9w0BAQEFBAOCAQ8AMIIBCgKCAQEAngAPZy+xJRhwzyC3NuiDQ6mXXhHD797wGt8L91v7jU+IZigggiRJIYOHwEUVkvPKErULIi8ZQhi2pykuSoJu6733GUoqct22M9uYOe9I5Y+9uL16dSVrn90Vy2vk9/CqAC+cKbIdEMpowhb/nap7e9+m8owcttH0trkWV1qMSTrQIIsIAo48jxLfxjtOLHwyCGE4JOSvBg3RSNUWVH7SAwk5b3zv0JM2lV1ctF2kiDs1RP2ASXgLnCjCUH6EdXfbgORrImd58kO+931RbdhGwPUlt8+ij6UxvE6kJBm9wnIBVyiDrRmPcuHd41hCFooMEmoCRxr1ZGDxcTEh3DndUwIDAQAB",
"encryption-cipher-type": "RSA"
}
}
#
Format of encrypted data
- Encrypted values are stored and displayed via RESTCONF or UniConfig shell with the 'rsa_' prefix. The prefix is used by UniConfig to see if posted data is encrypted already or needs to be encrypted.
- The encrypted string is encoded using Base64 encoding.
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=dev01/config/secret' \
--header 'Accept: application/json'
{
"secret": "rsa_TrmM1CFS3nSWnNqVYL4SYCF2I8rvMBg+zsN8iMXq3o/GQwcU2DTTMpLix9LpMsbXO9JsGq06jAy8nTIl80hv7g=="
}
#
Example: global-device model
The next use-case shows encryption of values marked by 'frinx-encrypt:encrypt' extension on both UniConfig server side and device side. NETCONF device directly exposes 'frinx-encrypt' YANG module and leaves with applied extension (side-loading of encrypted paths is not necessary).
Used YANG model for simulation of YANG device:
module config {
yang-version 1.1;
namespace urn:ietf:params:xml:ns:yang:config;
prefix config;
import frinx-encrypt {
prefix fe;
revision-date 2021-12-15;
}
revision 2021-12-15 {
description "Initial revision";
}
typedef secret-string {
type string;
}
container keys {
config false;
leaf public-key {
type binary;
}
}
container config {
leaf test {
type string;
}
list properties {
key property-id;
leaf property-id {
type string;
}
leaf enabled {
type boolean;
}
leaf value {
type string;
fe:encrypt;
}
}
container routing {
container rip {
leaf version {
type uint8;
}
leaf auto-summary {
type boolean;
fe:encrypt; // only string is supported for encryption - ignored
}
}
container eigrp {
leaf process-id {
type uint16;
}
leaf password {
type secret-string;
fe:encrypt;
}
}
leaf-list neighbor-key {
type leafref {
path "../../properties/value";
}
fe:encrypt;
}
}
}
}
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/connection-manager:install-node' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
"input": {
"node-id": "testtool",
"netconf": {
"netconf-node-topology:host": "127.0.0.1",
"netconf-node-topology:port": 36000,
"netconf-node-topology:keepalive-delay": 5,
"netconf-node-topology:max-connection-attempts": 1,
"netconf-node-topology:connection-timeout-millis": 60000,
"netconf-node-topology:default-request-timeout-millis": 60000,
"netconf-node-topology:tcp-only": false,
"netconf-node-topology:username": "admin",
"netconf-node-topology:password": "admin",
"netconf-node-topology:sleep-factor": 1.0,
"uniconfig-config:install-uniconfig-node-enabled": true,
"uniconfig-config:uniconfig-native-enabled": true,
"uniconfig-config:crypto": {
"public-key-path": "/keys/public-key"
}
}
}
}'
{
"output": {
"status": "complete"
}
}
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/uniconfig-manager:create-transaction'
5e75d4e9-382e-4852-905e-9b5c4db57107
curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/properties' \
--header 'Content-Type: application/json' \
--header 'Cookie: UNICONFIGTXID=5e75d4e9-382e-4852-905e-9b5c4db57107; Path=/rests/' \
--data-raw '{
"properties": [
{
"property-id": "id1",
"enabled": true,
"value": "test1"
},
{
"property-id": "id2",
"enabled": false,
"value": "test2"
}
]
}'
Status: 201
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/properties?content=config' \
--header 'Accept: application/json' \
--header 'Cookie: UNICONFIGTXID=5e75d4e9-382e-4852-905e-9b5c4db57107; Path=/rests/'
{
"properties": [
{
"property-id": "id1",
"value": "rsa_hJVw+MLPnB4K9dlH67khBXMt8LW7p2+oXCFLVq19TelOVXf4Oad6XfO36wD4gTjF0VpgGp3/95SYX25NrBT5U8vW8AQ33OdFo99TF+g+bAjYE8bBX9ND8Nwdyxu86AKmPGzJWHKlz3SIf0KzX+hC9LvdDiD4nmkPiS27ZGVOnaN9wNFHEt9Oa9Z4SvKSPq8ZpxVoCpHfZ08CS7DPuMqaMRPzi+7QWIsMSIBXoNbWDlg5YTN68tgcOCwtof1lSYaZHnpNWHAvR59HMh2vL+L4BWRvnQgVWoYYuC3aPWMbF+Z8Q5CVqdzcD67VUzhKcGKEiag9u1suy0IBTLAhJPHD+g==",
"enabled": true
},
{
"property-id": "id2",
"value": "rsa_YMoUZ5fOIYA8Uii34hg+CJ5BsEGlu82y0MJDb8ETbz3lcnlDxevrVLHtT6TdwkU+6wUed80FRfrD9FCPWfq6E19hC7fyq9kV8nS7IO02kuafZ0fsKIFKHSQqsOJTe9dACOunWmo6ZqzRjUHn2tVBY0rrydtusk7fJ4GrmK8X73e3EXOlWYOtqxZj88Egf6FrrpN17sJZJCHMHI+tN0GMEykjYhklnW2QxaLyXjrI88PcJwPUEOQouG5tSOVDw7xAKu/yPGikTUrlIZGaT7PJTXkKOMC8TomJybVD7mA8e9ytcJO4jQVJD10JxO2PJe1L1humgi4qbOzv3xQ+Mmsfhg==",
"enabled": false
}
]
}
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/uniconfig-manager:commit' \
--header 'Accept: application/json' \
--header 'Content-type: application/json' \
--header 'Cookie: UNICONFIGTXID=5e75d4e9-382e-4852-905e-9b5c4db57107; Path=/rests/' \
--data-raw '{
"input": {
"target-nodes": {
}
}
}'
{
"output": {
"node-results": {
"node-result": [
{
"node-id": "testtool",
"configuration-status": "complete"
}
]
},
"overall-status": "complete"
}
}
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/config/properties?content=config' \
--header 'Accept: application/json'
{
"properties": [
{
"property-id": "id1",
"value": "BsscbpHaTAR3JBnUjuWPcIiUXmpakK9rvmEiTh5+yInezkzIEPQJNyIlVONMjRABv2cs5a0rIfcJAIpwKfmGwB1hfPRSYEUJrMuvSY2SvOhgEAYAcVrMGsVLtmSpZymvDQw1ZUAp1ANT2r3NgH+FELWmATaGmKMtBJLyt8OexXmpCmENmGf+Hdj0450a6WwW+qPcJnLclR+KUR6yHSOzIZVPGBdp0zw5bEwCsYPWLtBgEw4U9/QxzO+ELhO8o9bEJx44EVax5zSZpmr5+9TineRB99GLaBpTnbDEUDKB6qDzmmutuQfaqUCdIpeBPOHIkY2R1Eos2Bagx2mAv/QXWw==",
"enabled": true
},
{
"property-id": "id2",
"value": "UM3pBX/zsmwBoYUQPFLMl3XciPIbAKU2Z3rFlDaHNWotxwjci2Sc4E42Mz/hfTBbJOsrDhwDf9542dUcnNZ0VQZHSZ6QSm8YZYkLgwTC0jIz+kC/aLP8yHdax8pSUrWf1oqGgYAD18wC6CLL8Jvptu4YFH7oxxVAk1b6RX3LcU41UMrxbGTdkPq8iUAMgI5d3+YKVRzy00xOAyhMo3rrRK6VDtTZ+jwxvTK4V9xo7AEgxjCQXhEnTQPWVESGRiq0WP4wRX4QlwB6b7uiwcQYa+L6ZGU83CJeA8fDb9YSsRzKkIQJ+6cKaiNXupvDTn7nMy0lhG45oJfGUB059RAaKQ==",
"enabled": false
}
]
}
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/properties?content=config' \
--header 'Accept: application/json'
{
"properties": [
{
"property-id": "id1",
"value": "rsa_hJVw+MLPnB4K9dlH67khBXMt8LW7p2+oXCFLVq19TelOVXf4Oad6XfO36wD4gTjF0VpgGp3/95SYX25NrBT5U8vW8AQ33OdFo99TF+g+bAjYE8bBX9ND8Nwdyxu86AKmPGzJWHKlz3SIf0KzX+hC9LvdDiD4nmkPiS27ZGVOnaN9wNFHEt9Oa9Z4SvKSPq8ZpxVoCpHfZ08CS7DPuMqaMRPzi+7QWIsMSIBXoNbWDlg5YTN68tgcOCwtof1lSYaZHnpNWHAvR59HMh2vL+L4BWRvnQgVWoYYuC3aPWMbF+Z8Q5CVqdzcD67VUzhKcGKEiag9u1suy0IBTLAhJPHD+g==",
"enabled": true
},
{
"property-id": "id2",
"value": "rsa_YMoUZ5fOIYA8Uii34hg+CJ5BsEGlu82y0MJDb8ETbz3lcnlDxevrVLHtT6TdwkU+6wUed80FRfrD9FCPWfq6E19hC7fyq9kV8nS7IO02kuafZ0fsKIFKHSQqsOJTe9dACOunWmo6ZqzRjUHn2tVBY0rrydtusk7fJ4GrmK8X73e3EXOlWYOtqxZj88Egf6FrrpN17sJZJCHMHI+tN0GMEykjYhklnW2QxaLyXjrI88PcJwPUEOQouG5tSOVDw7xAKu/yPGikTUrlIZGaT7PJTXkKOMC8TomJybVD7mA8e9ytcJO4jQVJD10JxO2PJe1L1humgi4qbOzv3xQ+Mmsfhg==",
"enabled": false
}
]
}
curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/routing/neighbor-key' \
--header 'Content-type: application/json' \
--data-raw '{
"neighbor-key": [
"neigh1",
"neigh2",
"neigh2"
]
}'
Status: 201
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/config/routing/neighbor-key?content=config' \
--header 'Accept: application/json'
{
"neighbor-key": [
"JD+6+DCBf97NIJqxekkrpdspQzgpZ9/G9ckV39hmnLyUS2rc7KULFMX/zw6drLsyV8ZgKyLXUjA0aiQq0k2FvicujJAAwSX/GRjKkN51P/kV4AA0hTxX1eVOC3RR392lRCzRmcIaaniHj9zXOJciY/Ki5UvKW0VOwcaPN47iZKJ2fcBbyNwMcQfXAP0ScBQOCxH/MVtp7vq/0tJCS6CS4CSNOx/LarSaq+MGgKgQroWQ9LONnJ5BCWsZsO6h5RhhBOjn5AT4cNrmvEAvbGohkTJCibdSmAO28AfIdVqidoRABGA8z8fEOu0vgdFmKXJFaawE7kpZBgvnm3EN5nr/6A==",
"X24s8vRw3tJB6pK5cLaT6SnFXoGG1HlMUOs91k8DCGSVxMlV98l5W3WWnGEuQnJdH8n6dNhC3qaXO4vEd2CUT97HnMpP25mbKvBuJot12xoMj7lMDg+J0+FuhKiy+ibim1o059wbbayAU7IsxiKIVgbHIwVovI5vub331Ya5TGpuUVOAMRXasnvymGRbbWuS2aTkwDWt/148549C9ofTqOr0kFL0TVD+Ze8BSdi33+GKTskAvrk44vNJjZI/mITggWezHKi2xfu8R+vEK+pCaelcjmMuwYXYEu6l+fI8E+wU9/CRAK/EpGHjBKljuae8Q1UmeY3TeQ8/ahwCw1UqLQ==",
"RoG/5szzENbFh0/ZWhw+f8Wg+dQyXpQ1RR2rIEfLOBZkVkNq55LTuB0NwgLfw/PBirUZVZHtPzGNMmOnuqoyfRZ8AUu8t6mgxaKKRROAaEKQOJ069Gl5klRn4kryMzDLihcoHWfnJqcb+SbQ8SIoeeUZdd0yJkgkegJMYWyWECOGbWlPX7YaKg7sd6QWzHh+SBXyZg5tYyG5qm7i6XiXysyB1CAtuQRLk2EKkE4Ce5Wo6+JT2vflx3x+CcQAB3qH6ZAa4Mc5TzPSsajTlJ+yxicKvKGz3HuV5c6qn7961+pADXlpuiV69O1nK8+yh+3+NdFE/7THpoy5FkmQ70/hGg=="
]
}
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/routing/neighbor-key?content=config' \
--header 'Accept: application/json'
{
"neighbor-key": [
"rsa_DLvDUR3de+dqdOw3/MwokDVFa2yuw3kySFYIMFZ4Fk61F3Fp4DU5ePFxu5J1tWPeJWs769Ms11/ugTbE7SSKd5kB+NaJv2pjvsnaEg06DDXw46hEM5OiAMsW0XbkkqC1jAP2locXZRgt095x0mNV9o8ssIhLwwvw7QC625CnWma/L3fmDbk7ZyvpyAdyovkLbY2b5IbO3Iusbtkga41cTmRKbtjZ7h9fMzVSVunWj2Q4X8nwihinUI7ytiPWFvpZ9Ehhldth8kVs8t4XiRjrzSPGDsqR7jg0NnGJQMFpXxG/QVkhZSJhegxFVBvAwhTOSfu19mfR7ghSR8pYRKEtbQ==",
"rsa_RP9tOlIDgBo2rIHoQ+JFyYVDHs69cDAh8i+2Upml+/i1XDAku6L7oCj2nQNPmutiv/GNoDZo7K3Zoq1tff8N3eqB+xVtkIyYY2YsURJb6GGOlEKRYAUtVGdVxdTnxiie19FCasNrabI/+HgU9KLopjCb9jkuDg2m/pbn14rdzM5JT0XSiuInj6jvKT4qf+/mt4tqrpPT/Y1XePAOTNotZMMXu5ocSV6gxLUk360/Eo19Lv0qSNRLis5xIpjtFPWkF1po13kM3F9kq5QeVB41XbU9ZcTpBi/EeQLmcX0JeDZiIhrSVSmrMw0JsnHlv8V550Jo8rWr/v3Q8hXpgCPr0Q==",
"rsa_kgG8T63FBrtvORJl80HJZ86y/QTnOsOCqebNyEV1nJGgszIffUS3DrZk/xBz1ldeChMGbEzz0M7ERD9Lg7LAQGwbdci0ZlbXufdSDdGR0PTCfSly/kq2AQ6748ZQhSiEO6wjY1I5ADh3xJJoWaZTb7C9RM6YgezCQweJt41N6Yr4NMhAIEjto4b4iuHv6MjTLLOsjJKkGFZRzPZBo5B/ojMWqrBVBLc5lQqfeJ4vF2jNRaNMlLsh0wttekMjqcdBanpQh4Nov0KvCQ5Y5u4rzAQ/IS3MdD0A+fUioTW1wZhcvsi4b8Us0pIQ1lQmQVZCR/4F/YnuvuraSxq53ln+nA=="
]
}
#
Example: global-only model
The next use-case shows encryption of values marked by 'frinx-encrypt:encrypt' extension only on UniConfig server side. NETCONF device directly exposes 'frinx-encrypt' YANG module and leaves with applied extension (side-loading of encrypted paths is not necessary).
Used YANG model for simulation of YANG device is same as in the previous use-case.
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/connection-manager:install-node' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
"input": {
"node-id": "testtool",
"netconf": {
"netconf-node-topology:host": "127.0.0.1",
"netconf-node-topology:port": 36000,
"netconf-node-topology:keepalive-delay": 5,
"netconf-node-topology:max-connection-attempts": 1,
"netconf-node-topology:connection-timeout-millis": 60000,
"netconf-node-topology:default-request-timeout-millis": 60000,
"netconf-node-topology:tcp-only": false,
"netconf-node-topology:username": "admin",
"netconf-node-topology:password": "admin",
"netconf-node-topology:sleep-factor": 1.0,
"uniconfig-config:install-uniconfig-node-enabled": true,
"uniconfig-config:uniconfig-native-enabled": true
}
}
}'
{
"output": {
"status": "complete"
}
}
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/uniconfig-manager:create-transaction'
782eb86d-3c11-4c77-bfdf-e8b0bf283830
curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/properties' \
--header 'Content-Type: application/json' \
--header 'Cookie: UNICONFIGTXID=782eb86d-3c11-4c77-bfdf-e8b0bf283830; Path=/rests/' \
--data-raw '{
"properties": [
{
"property-id": "id1",
"enabled": true,
"value": "test1"
},
{
"property-id": "id2",
"enabled": false,
"value": "test2"
}
]
}'
Status: 201
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/properties?content=config' \
--header 'Accept: application/json' \
--header 'Cookie: UNICONFIGTXID=782eb86d-3c11-4c77-bfdf-e8b0bf283830; Path=/rests/'
{
"properties": [
{
"property-id": "id1",
"value": "rsa_G+a03obgOIUJ0iVZRj5raw6umiDGCfmiaoufAw7QhqI/T7EH6ZSv+yV+7QgPqj278gjtC9Dy8ajTDihI8CMQstpXUrWPHnQe9KfgBfcepL7BBfYJUluJJzCdAXwlwDi7eab9VPBIyBEtz7+S/jqycbjRCBILWrJT7jxw7Pba9ar49KuaHYkclau6L6baOkbNSnF9VeQjecz51EUS5aOPvXghHzYlcHdLdkoEKoFUfEdD0UzY679cPyMojJ2bZzpdRwIIrZQRcXQxhFNIMGwuKlY0TaHF5215A68I3gbtr0/zSWu4EVZbYP8UCLKR7RdiOnbonrjB5tfekCn/1FnqSQ==",
"enabled": true
},
{
"property-id": "id2",
"value": "rsa_dqORW1ld4lf8PPnGSXhkVIoL9/i1uH9s8mKtEINmt4N1wC3pmSElhqC06Al/TdvN/ocjOcQd8J3ULw9eDh1fnfiggMofhVsFYtQTl90pGtiZ47pMy23gWNHYf3VSBNJQTmGVPc2QV8AJVcgvZSknjlLqUW9yQ5mVPrU6NOHQSfB7ba6gp5wdY1iwnEJcrD4LYbeBzHhrrMr3QNUNSaeEyD/FHEoqzsl7p7wWIOvLZhhqiKfqkov86TGfD3U0MZE+j4FfSifxrEZQPh2O8UHMJ4ir2wFMB5TeDTqEFdBHEo1m/vlzh41dPReUVTU+/hf9Zzw2YSnaxh8ZvC4FW2bieQ==",
"enabled": false
}
]
}
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/uniconfig-manager:commit' \
--header 'Accept: application/json' \
--header 'Content-type: application/json' \
--header 'Cookie: UNICONFIGTXID=782eb86d-3c11-4c77-bfdf-e8b0bf283830; Path=/rests/' \
--data-raw '{
"input": {
"target-nodes": {
}
}
}'
{
"output": {
"node-results": {
"node-result": [
{
"node-id": "testtool",
"configuration-status": "complete"
}
]
},
"overall-status": "complete"
}
}
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/config/properties?content=config' \
--header 'Accept: application/json'
{
"properties": [
{
"property-id": "id1",
"value": "test1",
"enabled": true
},
{
"property-id": "id2",
"value": "test2",
"enabled": false
}
]
}
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/properties?content=config' \
--header 'Accept: application/json'
{
"properties": [
{
"property-id": "id1",
"value": "rsa_G+a03obgOIUJ0iVZRj5raw6umiDGCfmiaoufAw7QhqI/T7EH6ZSv+yV+7QgPqj278gjtC9Dy8ajTDihI8CMQstpXUrWPHnQe9KfgBfcepL7BBfYJUluJJzCdAXwlwDi7eab9VPBIyBEtz7+S/jqycbjRCBILWrJT7jxw7Pba9ar49KuaHYkclau6L6baOkbNSnF9VeQjecz51EUS5aOPvXghHzYlcHdLdkoEKoFUfEdD0UzY679cPyMojJ2bZzpdRwIIrZQRcXQxhFNIMGwuKlY0TaHF5215A68I3gbtr0/zSWu4EVZbYP8UCLKR7RdiOnbonrjB5tfekCn/1FnqSQ==",
"enabled": true
},
{
"property-id": "id2",
"value": "rsa_dqORW1ld4lf8PPnGSXhkVIoL9/i1uH9s8mKtEINmt4N1wC3pmSElhqC06Al/TdvN/ocjOcQd8J3ULw9eDh1fnfiggMofhVsFYtQTl90pGtiZ47pMy23gWNHYf3VSBNJQTmGVPc2QV8AJVcgvZSknjlLqUW9yQ5mVPrU6NOHQSfB7ba6gp5wdY1iwnEJcrD4LYbeBzHhrrMr3QNUNSaeEyD/FHEoqzsl7p7wWIOvLZhhqiKfqkov86TGfD3U0MZE+j4FfSifxrEZQPh2O8UHMJ4ir2wFMB5TeDTqEFdBHEo1m/vlzh41dPReUVTU+/hf9Zzw2YSnaxh8ZvC4FW2bieQ==",
"enabled": false
}
]
}
curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/routing/neighbor-key' \
--header 'Accept: application/json' \
--data-raw '{
"neighbor-key": [
"neigh1",
"neigh2",
"neigh2"
]
}'
Status: 201
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/config/routing/neighbor-key?content=config' \
--header 'Accept: application/json'
{
"neighbor-key": [
"neigh1",
"neigh2"
]
}
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=testtool/configuration/config/routing/neighbor-key?content=config' \
--header 'Accept: application/json'
{
"neighbor-key": [
"rsa_gq4bEcMd45BAr4aT2M4bCUvYyJHmMDIJzepeKWQoK05POgZRQyxpz1wTYbeaAju+SQnFphShibIYULjKtuCRXiL6w4mt7JaAxQJwrNN9DeZrypDKWTl5sIXB7r3VCRplfqQUByzXseWbMiwJGq/StboWAnq2YMiFm1DcZVwquymMRGwQl2cwPzZXRkoAVruaEpmOyIOI0fun3u2EkPuagpGT+wB4MRhB3WcsZ7e7ieAQPdjosUoNhoSdZZcwISwXG2ken1bSyEXWYKTvGyHTopq+PhfDKWqTZ09kOr+ufyGfN+rYSQvar2Q3+J02TMb9eMD161f7RO06BBviSXGwVQ==",
"rsa_jdX0haiadPEl2psy1pfwU4xWNyy4g0PA+QTUzJeWPtOVz4lMj6HfiGypWvpNNTaVdpOfb0R5cx6ns+i+oPWPEesodWreTj5BYX42xyFINzcB2zTbNzAOFE8zpeKNHweA0a3kDVCvJOYF5haGSA8ggjzu/ajxi6dN4hDXN9e8ixThB2hB8/Yhss6xK6Tmbxx9syajAqh3HqF9r5/IctBcQkeDAQ0XyVqjJztK6aPx2hDFZ/qSnxS8Mt+zN+rLgUuaY2SaNdEZG3lkQZyRpzlMNyNqebB8anTwtuFd4NtpAHprEVnv7f4Mnvvcj7xR1Cxld4GfmXTSljhBzKzV4cPIrQ==",
"rsa_hgeLRb889fVXV96z2fEVaMZ/QGeFIZk9Jv9Nexjl06NqWhBn7j8RwDE/ygL1OUifWDd6xj0aRc3F6AhJR/SJHNvHDaltmHK5UqA0iYVR4kxElWi/XI3Q/aNJela1HGURc6sIv1VdEyDrlJ8r80i+wHSbxi/EG10tCYK+HkJDUQ8nTQ7T337QBRKlGDowz2CPrwSM72VBJUgax1IiFI8JW2757pxK8uyZM7q+u+Wl1M+MuTPumNEBmzwULaIgx9jNjiQkrLwQqEMS+x8igDgBaglQPOPHxRNEWt6zaKQcacFXWfdYDWMZogtJNu4wEbSFYM5UiojjqPLGzNTSAdEFfQ=="
]
}
#
Data hashing
UniConfig supports 'iana-crypt-hash' YANG model for specification of hashed values in data-tree using type definition 'crypt-hash'. Hashing works in the 'uniconfig' and 'unistore' topologies. Only NETCONF devices are currently supported because CLI cannot be natively used for reporting of device capabilities that would contain supported hashing function.
#
Architecture
Hashing is done only in the RESTCONF layer after writing some data that contains leaves/leaf-lists with 'crypt-hash' type. Afterwards, UniConfig stores, uses, and writes to device only hashed representation of these values.
#
YANG support
YANG module 'iana-crypt-hash':
http://www.iana.org/assignments/yang-parameters/iana-crypt-hash@2014-08-06.yang
All 3 hash functions are implemented - 'MD5', 'SHA-256', 'SHA-512'. In case of 'uniconfig' topology, hashing function is selected based on reported feature in the NETCONF capability, in case of 'unistore' topology, UniConfig enforces 'SHA-512' hashing function.
#
Device installation
Hashing is enabled by default on NETCONF devices that reports corresponding 'iana-crypt-hash' model-based capability. User doesn't have to add entry setting in the 'install-node' request.
After successful installation of device, it is possible to check loaded hashing function that will be used for storing of hashed values. Use following GET request:
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=dev01/crypto:hash?content=nonconfi' \
--header 'Accept: application/json'
{
"hash": {
"algorithm": "SHA-512"
}
}
#
Example: hashing input values
This example demonstrates hashing of input values with 'crypt-hash' type on RESTCONF API.
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/uniconfig-manager:create-transaction'
1ed7ea30-362e-4297-a93f-b1c35b3f376d
curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=dev01/configuration/system/users=frinx' \
--header 'Content-Type: application/json' \
--header 'Cookie: UNICONFIGTXID=1ed7ea30-362e-4297-a93f-b1c35b3f376d; Path=/rests/' \
--data-raw '{
"system:users": [
{
"name": "frinx",
"role": "admin",
"login": "shell",
"password": "secret"
}
]
}'
Status: 201
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=uniconfig/node=dev01/configuration/system/users=frinx?content=config' \
--header 'Accept: application/json' \
--header 'Cookie: UNICONFIGTXID=1ed7ea30-362e-4297-a93f-b1c35b3f376d; Path=/rests/'
{
"system:users": [
{
"name": "frinx",
"role": "admin",
"password": "$6$Nmd5tbv5KOkc9lud$gK6NX6Sj/5gZwdhEh6I9Ff0z0CBpIiXDYwjB9U8vIG4cQM/bWFCfcAQlKmlt86NFfZ0megJGX67UealuD95wB0",
"login": "shell"
}
]
}
curl --location --request POST 'http://127.0.0.1:8181/rests/operations/uniconfig-manager:commit' \
--header 'Accept: application/json' \
--header 'Content-type: application/json' \
--header 'Cookie: UNICONFIGTXID=1ed7ea30-362e-4297-a93f-b1c35b3f376d; Path=/rests/' \
--data-raw '{
"input": {
"target-nodes": {
}
}
}'
{
"output": {
"node-results": {
"node-result": [
{
"node-id": "testtool",
"configuration-status": "complete"
}
]
},
"overall-status": "complete"
}
}
curl --location --request GET 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=dev01/yang-ext:mount/system/users=frinx?content=config' \
--header 'Accept: application/json'
{
"system:users": [
{
"name": "frinx",
"role": "admin",
"password": "$6$Nmd5tbv5KOkc9lud$gK6NX6Sj/5gZwdhEh6I9Ff0z0CBpIiXDYwjB9U8vIG4cQM/bWFCfcAQlKmlt86NFfZ0megJGX67UealuD95wB0",
"login": "shell"
}
]
}