gNSI

gRPC Network Security Interface (gNSI) is a set of RPCs that allow a client to define the security configuration of a device and to retrieve security information. gNSI is maintained by the OpenConfig project on Github, and contains a set of RPCs as well as extensions to gNMI and the OpenConfig YANG modules.

SR Linux supports the following gNSI services:

gNSI Authz service

The gNSI Authz service allows clients to configure and manage a gRPC-level authorization policy that defines which users can access which gRPCs on the target node. This policy is defined by a JSON string and controls access to all gRPC servers to prevent access from malicious actors.

Note: Only one policy is active for the entire system.

Unlike role-based access control, which provides authorization of system YANG paths, the Authz service authorizes the use of individual gRPCs; for example access to the /gnmi.gNMI/Get RPC, rather than to any individual path that the Get RPC can retrieve.

Typical Authz service steps

In the typical Authz service process, the client performs the following steps:

  1. Upload the authorization policy by sending an UploadRequest to the target node using the Rotate RPC.
  2. Verify that the authorized users can access the required gRPCs (and that non-authorized users are denied) by sending a ProbeRequest using the Probe RPC.
  3. Lock in the updates by sending a FinalizeRequest using the Rotate RPC.
  4. As required, retrieve details of the currently active policy by sending a GetRequest using the Get RPC.

Authz policy

The Authz policy consists of the following:

  • name: name for the policy defined by the client
  • allow_rules list (mandatory): list of allow rules for the policy
  • deny_rules list (optional): list of deny rules for the policy

Allow and deny rules

Each allow or deny list is comprised of instances of rules. Each rule consists of the following:

  • name: name for the rule defined by the client; similar to the policy name
  • source: a holding container with a single source type of principals:
    • principals: a list of principals that must match against user objects, be it one of the users defined in system aaa authentication user, a remotely resolved user from a system aaa server-group, or the admin
  • request contains:
    • paths: a list of gRPC RPC paths (in format pkg.Service/Rpc) that this policy applies to; for example: /gnoi.os.OS/Install (if no paths are provided, all paths are matched)
    • headers: a list of key/value pairs matching HTTP headers
      Note: SR Linux does not support matching on headers.

Matching source and request

Both the source and request fields must match in order for a rule to match. If both source and request are empty, the rule always matches. Empty source and request can serve as a wildcard in a deny_rules list to deny all RPCs or in an allow_list to accept all RPCs except those matching in the deny_rules list.

If only the source is empty, the paths provided in the request field apply to all users system wide. Similarly if only the request is empty then the action (deny or allow) is applied to all users provided in the source. If no paths are specified in the request, all paths are matched.

Authz policy example

The following shows an example policy in which two administrators Alice and Bob have the ability to execute any of the gNSI Authz RPCs.

{
  "name": "gNSI.authz policy",
  "allow_rules": [{
    "name": "admin-access",
    "source": {
     "principals": [
      "spiffe://nokia.com/sa/alice",
      "spiffe://nokia.com/sa/bob"
      ]
    },
    "request": {
      "paths": [
        "/gnsi.authz.Authz/*"
      ]
    }
  }]
}

Authz policy persistence

As it is a requirement to persist a policy after it has been finalized, on finalization the current policy is written to /etc/opt/srlinux/gnsi/authz-policy.json. This policy is read by the SR Linux gNSI server on startup and exposed as the active policy.

It is an Authz requirement that if a policy is configured, no gRPC servers (this includes P4RT, gRIBI, gNOI, gNMI, and gNSI externally) can start until the policy is successfully activated. The Authz scope is to protect access to system RPCs from malicious entities, so a policy must be active before ports are opened.

Default Authz policy

As part of the default SR Linux configuration, the Authz service is running, and a default Authz policy controls access to every active gRPC service. The result of the default policy is that any authenticated user is permitted full access to any currently active service and gRPC. This does not overrule any subsequent role-based access control that exists on the system.

 {
  "name": "Default policy", 
  "deny_rules": [],  
  "allow_rules": [    
   {                  
    "name": "admin-access",  
    "source": {   
     "principals": [   
      "*"  
     ]   
    },    
    "request": {   
     "paths": [    
      "/*",     
      ""      
     ],    
     "headers": []    
    }    
   }    
  ]   
 }

Authz authorization logic and interactions

To validate a gRPC authorization, gNSI performs the following actions:

  1. Check the user and RPC combination against any deny_rules. If a match is found, the request is denied. If no match is found or there are no deny_rules, execute the next step.
  2. Check for a match against any allow_rules. If a match is found, the request is permitted. If no match is found, deny the request.
Note: The gNSI Authz behavior differs from role-based access control, in that, if any deny_rules are matched, then the request is denied, even if a more specific path exists in allow_rules.

Authz interactions with role-based access control and service authorization

The Authz service operates in addition to existing role-based access control and service authorization. As a result, to provide a user access to a gRPC, you must configure their access under role-based access control and service authorization (for example, system aaa authorization role services gnmi) in addition to enabling access using the Authz service. The system aaa authorization role services command also supports defining service authorization for gnsi.

Order of authorization

The order of authorization is as follows:

  1. Check service authorization first; only if the user is authorized for the service are they admitted.
  2. If the interface is a gRPC interface, check the Authz policy to see if the user is authorized for the specified RPC.
  3. If the user is configuring or reading any paths, perform role-based access control.

Default TLS profile

To allow the gNMI (and gNSI) server to start as part of the default configuration, the factory default configuration includes a TLS profile named __default__. This default policy does not authenticate the identity of connecting clients. You can view the policy using the info from state system tls server-profile __default__ command.

# info from state system tls server-profile __default__
   system {
        tls {
            server-profile __default__ {
                key $aes1$4lL6SVq5G8=$FqANWbk8TQmrGYB1cTuaplFUZTZlAP992Debrq4X2ZjfOde4wA
                ...
                certificate "-----BEGIN CERTIFICATE-----
MIIFLzCCAxegAwIBAgIUBQFYPrWyBalNUfTNCBUAMiWrk2kwDQYJKoZIhvcNAQEL
BQAwHTEOMAwGA1UEAwwFc3JsZDUxCzAJBgNVBAYTAlVTMCAXDTI0MDIyMDIzNTY0
...
-----END CERTIFICATE-----
"
                authenticate-client false
                dynamic true
                cipher-list [
                    ecdhe-ecdsa-aes256-gcm-sha384
                    ecdhe-ecdsa-aes128-gcm-sha256
                    ecdhe-rsa-aes256-gcm-sha384
                    ecdhe-rsa-aes128-gcm-sha256
                ]
            }
        }
    }

SR Linux also supports a default TLS configuration option for the gRPC server (system grpc-server name default-tls-profile [true | false]) that controls whether the system uses the default TLS profile if none are configured using the tls-profile option. If default-tls-profile is set to false (the default value), and no tls-profile is defined, then TLS is disabled entirely from the system.

Rotate RPC

The Authz Rotate RPC allows a client to replace an existing gRPC authorization policy on the target node.

If any steps in the Rotate RPC process fail, the target node rolls back any changes made by the RPC.

Only one Rotate RPC can be in progress at a time. If a client attempts to call the RPC while another call is already in progress, the second call is rejected with a gRPC error of UNAVAILABLE.

Rotate RPC structure

rpc Rotate(stream RotateAuthzRequest) returns (stream RotateAuthzResponse);

Probe RPC

The Authz Probe RPC tests the currently active policy. It allows the Authz policy engine on the target node to provide a response to a specified gRPC call without actually performing the gRPC operation. The current policy can be one that has not been finalized, but this is not a requirement.

The Probe RPC expects a single ProbeRequest message, and returns a ProbeResponse. The ProbeRequest does not result in an actual gRPC call being made; it simply validates whether the call can succeed with the provided user and RPC information.

Probe RPC structure

rpc Probe(ProbeRequest) returns (ProbeResponse);

Get RPC

The Authz Get RPC returns the currently active gRPC authorization policy, as well as the policy version and created-on timestamp.

Get RPC structure

 rpc Get(GetRequest) returns (GetResponse);

gNSI Authz tools and state commands

To allow the gNSI Authz behavior to be invoked in the CLI or by a gNMI or JSON-RPC client, SR Linux supports the following tools commands:

  • tools system aaa authorization authz-policy clear
  • tools system aaa authorization authz-policy probe
  • tools system aaa authorization authz-policy remove
  • tools system aaa authorization authz-policy rotate
Note: Performing a rotate operation using the tools commands triggers an immediate finalization.

Clearing Authz policy counters using the tools command

To clear Authz policy counters, use the tools system aaa authorization authz-policy clear command.

Clear Authz policy counters
--{ candidate shared default }--[  ]--
# tools system aaa authorization authz-policy clear

Probing Authz policy counters using the tools command

To probe an Authz policy, use the tools system aaa authorization authz-policy probe command. The rpc parameter specifies which RPC to test, and the user parameter specifies which user to use for the test.

Probe Authz policy counters
--{ candidate shared default }--[  ]--
# /tools system aaa authorization authz-policy probe rpc /gnmi.gNMI/Get user admin
/system/aaa:
    Authz authorization policy version '1' action for user 'admin' and rpc '/gnmi.gNMI/Get' is ACTION_PERMIT

Removing an Authz policy using the tools command

To remove an Authz policy, use the tools system aaa authorization authz-policy remove command.

Given that there is only one system-wide gRPC authorization policy, this command reverts to the factory default authorization policy, which authorizes any gRPC call for every authenticate user.

Remove Authz policy
--{ candidate shared default }--[  ]--
# tools system aaa authorization authz-policy remove

Rotating an Authz policy using the tools command

To rotate an Authz policy, use the tools system aaa authorization authz-policy rotate command, which supports the following parameters:

  • created-on: sets the created-on value for the new policy
  • policy: specifies the gRPC authorization policy as a JSON-formatted string
  • version: specifies a version string to store with the policy

Unlike the Rotate RPC, the tools system aaa authorization authz-policy rotate command triggers an immediate finalization.

Rotate Authz policy
--{ candidate shared default }--[  ]--
# / tools system aaa authorization authz-policy rotate policy "{\"name\": \"foo\", \"allow_rules\": { \"name\": \"dev\", \"source\": { \"principals\": [
\"admin\", \"foo\", \"bar\" ] }, \"request\": { \"pat hs\": [ \"/*\", \"\" ] } } }" created-on 10 version 1
/system/aaa:
    Authz authorization policy has been rotated and finalized (version '' created on '1970-01-01T00:00:10.000Z')

Displaying the currently installed Authz policy

To display the currently installed Authz policy, use the info from state system aaa authorization authz-policy command.

Display the currently installed Authz policy
# info from state system aaa authorization authz-policy
    system {
        aaa {
            authorization {
                authz-policy {
                    version 2023-06-01
                    created-on "2024-02-16T17:29:08.721Z (40 minutes ago)"
                    policy "{
 \"name\": \"Default policy\",
 \"deny_rules\": [],
 \"allow_rules\": [
  {
   \"name\": \"admin-access\",
   \"source\": {
    \"principals\": [
     \"*\"
    ]
   },
   \"request\": {
    \"paths\": [
     \"/*\",
     \"\"
    ],
    \"headers\": []
   }
  }
 ]
}
"
                }
            }
        }
    }

gNSI Certz service

The gNSI Certz service allows a client to replace a certificate, trust bundle, certificate revocation list (CRL), or some combination of these artifacts on a target node.

Typical Certz service steps

In the typical certificate rotation process, the client performs the following steps using the Rotate RPC:

  1. Either generate the CSR on the client side, or direct the target node to generate the CSR using a GenerateCSRRequest.
  2. Obtain a signature for the certificate from the CA (out of band of the RPC).
  3. Upload the signed certificate to the target node using an UploadRequest.
  4. Verify (out of band of the RPC) that the services that use the new certificate bundle continue to operate normally.
  5. Send a FinalizeRequest to the target node to lock in the updates.

Entity messages

The Certz service uses Entity messages to define the Certz artifacts, which can be any of the following:

  • Certificate: An X.509 certificate and optional private key that is either PEM or DER encoded. The specific encoding is indicated in fields carried in children of the Entity message. A certificate also specifies any intermediate parent certificates. It is equivalent to the certificate displayed using the system tls server-profile name certificate command.
  • Trust bundle: The certificate bundle used to validate outbound connections, and inbound clients when mTLS is enabled. This is a typical system trust bundle available in /etc/ssl/certs. It is equivalent to the trust anchor displayed using the system tls server-profile name trust-anchor command.

  • CRL: The CRL bundle, which lists certificates that have been revoked and can no longer be used to validate connections. It is equivalent to the CRL displayed using the system tls server-profile name certificate-revocation-list command.

All together, these artifacts make up a single profile. In a single Rotate RPC call, a client can rotate all artifacts, or only specific artifacts.

To improve performance on the target node, certificates can be ordered. Groups of chained certificates (namely the trust-anchor and crl) appear last, and within the group, the root certificate must be the last certificate in the chain; for example: CertA, CertB, CertB-Root, CertC, CertC-Intermediate, CertC-Root.
Note: SR Linux can support an unordered bundle.

Default TLS profile

The default TLS profile is available at system startup and uses system-generated self-signed certificates and private keys. The default profile is saved to disk with other TLS profiles at /etc/opt/srlinux/tls. This default profile allows the gRPC server to start as part of the default configuration to meet the requirements of the Authz service.

TLS profiles can be populated using the Certz service or configured via the CLI using the system tls server-profile command. If a conflict exists in the configuration, the CLI configuration takes precedence.

Certz state paths

Certz state paths are available under system tls server-profile certz. These paths indicate the certificate, trust bundle, and CRL in use by each specific instance of a gRPC server.

The Certz JSON files are stored in /etc/opt/srlinux/gnsi, while the CRL PEM files are stored in /etc/opt/srlinux/tls.

Only users in the tls group can read these artifacts, and only the srlinux user can modify them.

Supported RPCs

SR Linux supports the following Certz service RPCs:

Rotate RPC

The Certz Rotate RPC allows a client to replace an existing certificate, trust bundle, CRL, or some combination of these artifacts on the target node. Either the target node or the client can generate the CSR for the new device certificate. If the client generates the CSR, it must also provide the corresponding private key with the signed certificate.

Only one Rotate RPC can be active at once. If SR Linux detects an additional Rotate RPC, it returns an error.

The Rotate RPC accepts a stream of RotateCertificateRequest messages and returns a stream of RotateCertificateResponse messages in response. A client uses the RPC to upload a certificate by specifying the certificate in a rotate_request before testing the new certificate (out of band of the RPC) and finalizing the result with a finalize_rotation. Until the target node receives the finalize_rotation, the change is transient and not persistent on disk. If the RPC is canceled for any reason before a finalize_rotation is received, then the system reverts all services using TLS to the previous values.

If the stream is broken or any of the steps fail, the target node rolls back to the original state, reverting any changes to any artifact.

Rotate RPC structure

rpc Rotate(stream RotateCertificateRequest) returns (stream RotateCertificateResponse);

Rotate RPC use cases

The following sections describe a number of Rotate RPC use cases each presenting the expected sequence of message exchange.

Case 1: Client generates the CSR and gets it signed
  1. The Rotate RPC stream begins.

    Client <------          Rotate() RPC stream begins          ------> Target node
  2. The client generates the CSR and gets the certificate signed by the CA (typically done before initiating the stream).

  3. The client sends the signed certificate with private key to the target node.

    The client can optionally include a trust bundle, a CRL, or both.

    Client ------>  UploadRequest(certificate, [trust_bundle],  ------> Target node
                            [certificate_revocation_list])           
    
    Client <------                UploadResponse                <------ Target node
  4. To validate that the certificate works, the client attempts to create new connections to the target node using the new certificate. If the new connections fail, the client cancels the RPC, forcing the target node to roll back all certificates included in the RPC.

    If a new CRL bundle is included in the UploadRequest in step 3, the client also attempts to establish new connections to the target node using the revoked certificates. In this case, failed connections validate that the certificates have been revoked.

  5. After successful validation, the client sends a final commit.

    Client ------>                FinalizeRequest               ------> Target node
Case 2: Target node generates the CSR and the client gets it signed
  1. Rotate RPC stream begins:

    Client <------           Rotate() RPC stream begin          ------> Target node
  2. The client sends a GenerateCSRRequest to the target node, and the target node provides the CSR in response:

    Client ------>              GenerateCSRRequest              ------> Target node
    
    Client <------              GenerateCSRResponse             <------ Target node
  3. The client obtains a signature for the certificate from the CA.

  4. The client sends the signed certificate without private key to the target node (the target node already has the private key because it generated the CSR).

    The client can optionally include a trust bundle, a CRL, or both.

    Client ------>  UploadRequest(certificate, [trust_bundle],  ------> Target node
                          [certificate_revocation_list])                      
    
    Client <------                 UploadResponse               <------ Target node
  5. The client tests and validates the certificate, using the same validation step as in Case 1.

  6. After successful validation, the client sends a final commit.

    Client ------>                 FinalizeRequest              ------> Target node
Case 3: Client changes only the trust bundle
  1. The Rotate RPC stream begins:

    Client <------             Rotate() RPC stream begin        ------> Target node
  2. The client sends a Certificate Authority Bundle chain to the target node.

    The client can optionally include a CRL.

    Client ------>           UploadRequest(trust_bundle,         ------> Target node
                            [certificate_revocation_list])           
    
    Client <------                   UploadResponse              <------ Target node
  3. The client tests and validates the certificate, using the same validation step as in Case 1.

  4. After successful validation, the client sends a final commit.

    Client ------>                   FinalizeRequest              ------> Target node
Case 4: Client uploads a CRL
  1. The Rotate RPC stream begins:

    Client <------           Rotate() RPC stream begin            ------> Target node
  2. The client sends a CRL bundle to the target node.

    Client ------>  UploadRequest([certificate_revocation_list])   ------> Target node
    
    Client <------                 UploadResponse                  <------ Target node
  3. The client validates the CRL by attempting to establish a new connection to the target node using the revoked certificates. Failed connections validate that the certificates have been revoked.

  4. After successful validation, the client sends a final commit.

    Client ------>                  FinalizeRequest                 ------> Target node

CanGenerateCSR RPC

The Certz CanGenerateCSR RPC tests whether the target node is able to generate a CSR given provided parameters. The CanGenerateCSR RPC consists of a single CanGenerateCSRRequest message and returns a CanGenerateCSRResponse. The client includes the parameters that it wants the target node to test for the CSR generation, including:

  • key_type: the algorithm used for generation of the key pair (for example, KEY_TYPE_RSA)
  • signature_algorithm_type: the signature algorithm used to generate the key pair (for example: SIGNATURE_ALGORITHM_SHA512_WITH_RSA)
  • certificate_type: the type of certificate to create (for example, CERTIFICATE_TYPE_X509)
  • key_size_bits: a uint32, indicating the size of the key in bits (for example, 2048)

CanGenerateCSR RPC structure

rpc CanGenerateCSR(CanGenerateCSRRequest) returns (CanGenerateCSRResponse);

AddProfile RPC

The Certz AddProfile RPC allows a client to add a new TLS profile to the target node. All elements of the added profile (certificate, CA trust bundle, and CRLs) are initially empty. The client must subsequently populate the artifacts using a Rotate RPC.

If a client attempts to add a pre-existing profile, the attempt is rejected with an error.

AddProfile RPC structure

rpc AddProfile(AddProfileRequest) returns (AddProfileResponse);

DeleteProfile RPC

The Certz DeleteProfile allows a client to remove an existing TLS profile.

The __default__ profile used by the gRPC server cannot be deleted. If a client attempts to delete the __default__ profile, the attempt is rejected with an error.

DeleteProfile RPC structure

rpc DeleteProfile(DeleteProfileRequest) returns (DeleteProfileResponse);

GetProfileList RPC

The Certz GetProfileList RPC allows a client to retrieve a list of the TLS profile IDs that are present on a target node.

GetProfileList RPC structure

rpc GetProfileList(GetProfileListRequest) returns (GetProfileListResponse);

gNSI Certz tools commands

To allow the gNSI Certz RPC behavior to be invoked in the CLI or by a gNMI or JSON-RPC client, SR Linux supports the following tools commands:

  • tools system tls server-profile <name> certz rotate
  • tools system tls server-profile <name> certz remove

Rotating a Certz profile using the tools command

To rotate a profile on the system, use the tools system tls server-profile <name> certz rotate command, which supports the following parameters:

  • certificate: specifies the new certificate to use
  • created-on: sets the created on value for the new policy
  • crl: specifies a bundle of certificates to add to the CRL
  • key: specifies the new private key to use
  • trust-anchor: specifies a certificate chain to use as a trust anchor
  • version: specifies the version string to store with the policy
Rotate Certz profile using tools command

The following example rotates the test-certz-profile with certificate test-cert, key test-key, CRL test-crl, trust anchor test-anchor, and assigned version of 1.

--{ candidate shared default }--[  ]--
# tools system tls server-profile test-certz-profile certz rotate certificate test-cert key test-key crl test-crl trust-anchor test-anchor version 1
/system/tls/server-profile[name=test-certz-profile]:
    Certz SSL profile 'test-certz-profile' has been added

/system/tls/server-profile[name=test-certz-profile]:
    Certz SSL profile 'test-certz-profile' has been rotated and finalized (version '1' created on '2024-02-16T16:20:03.000Z')

Removing a Certz profile using the tools command

To remove a profile from the system, use the tools system tls server-profile certz remove command.

Remove a Certz SSL profile using tools command
--{ candidate shared default }--[  ]--
# tools system tls server-profile test-certz-profile certz remove
/system/tls/server-profile[name=test-certz-profile]:
    Certz SSL profile 'test-certz-profile' has been removed

gNSI Certz state commands

Certz state paths are available under system tls server-profile. These paths indicate the certificate, trust bundle, and CRL in use by each specific instance of a gRPC server.

To display the currently installed Certz policy artifacts, use the following commands:
  • info from state system tls server-profile <name> certz certificate
  • info from state system tls server-profile <name> certz crl
  • info from state system tls server-profile <name> certz ssl-profile-id
  • info from state system tls server-profile <name> certz trust-anchor

Info from state for empty TLS server profile dyn

--{ running }--[  ]--
# info from state system tls server-profile dyn
    system {
        tls {
            server-profile dyn {
                dynamic true
                certz {
                    ssl-profile-id dyn
                }
            }
        }
    }

Info from state for rotated TLS server profile dyn

--{ running }--[  ]--
# info from state system tls server-profile dyn
    system {
        tls {
            server-profile dyn {
                key $aes1$ATQxUhdz4QGeu28=$HrE...
                certificate "-----BEGIN CERTIFICATE----- MIIGW...  ----END CERTIFICATE-----"
                authenticate-client true
                trust-anchor "-----BEGIN CERTIFICATE----- MIIFe...  -----END CERTIFICATE-----"
                dynamic true
                cipher-list [
                    ecdhe-ecdsa-aes256-gcm-sha384
                    ecdhe-ecdsa-aes128-gcm-sha256
                    ecdhe-rsa-aes256-gcm-sha384
                    ecdhe-rsa-aes128-gcm-sha256
                ]
                certz {
                    ssl-profile-id dyn
                    certificate {
                        version 7
                        created-on "2023-08-19T08:56:45.000Z (6 months ago)"
                    }
                    trust-anchor {
                        version 9
                        created-on "2023-08-19T14:53:09.000Z (6 months ago)"
                    }
                }
            }
        }
    }

gNSI configuration

SR Linux supports gNSI services using the gRPC server configuration. To enable gNSI support, enable the gRPC server and specify gNSI as one of the enabled gRPC services for a specified network instance (enabled by default on the mgmt network instance).

Like gNMI, the session between the gNSI client and SR Linux can be encrypted using TLS.

gNMI and gNSI servers enabled by default

By default, the gNMI and gNSI servers are enabled in the mgmt network instance.

# info system grpc-server mgmt    system {
        grpc-server mgmt {
            admin-state enable
            default-tls-profile true
            network-instance mgmt
            services [
                gnmi
                gnsi
            ]
        }
    }

Configuring gNSI services

As part of the gRPC server configuration, you can also specify which individual gNSI services to enable.

To enable gNSI services, use the system grpc-server <name> services command.
Note: If you enter services [gnsi] all gNSI services are enabled. To enable an individual service only, enter for example services [gnsi.authz] or services [gnsi.certz], and omit the [gnsi] parameter.

Enable gNSI services

# info system grpc-server mgmt
    system {
        grpc-server mgmt {
            admin-state enable
            network-instance mgmt
            services [
                gnsi
            ]
        }
    }

See the "Management servers" chapter in the SR Linux Configuration Basics Guide for related information about how to configure the gRPC server.