authz - openconfig/featureprofiles GitHub Wiki
Test gNSI API behaviors and gRPC authorization policy behaviors.
-
test_infra_id: the SPIFFE-ID that is used by test infra clients.
Configure the DUT to enable the following services (that are using gRPC) are up, and use mTLS for authentication:
- gNMI
- gNOI
- gNSI
- gRIBI
NOTE: the support of SPIFFE-ID should NOT require explicitly pre-configured local users in the DUT config (for the purpose of 1:1 mapping of each SPIFFE-ID to a local user).
Prepare the following certs with the specified SPIFFE ID. Cert format details can be found in SPIFFE PR
-
cert_user_adminwithspiffe://test-abc.foo.bar/xyz/admin -
cert_user_deny_allwithspiffe://test-abc.foo.bar/xyz/deny-all -
cert_gribi_modifywithspiffe://test-abc.foo.bar/xyz/gribi-modify -
cert_gnmi_setwithspiffe://test-abc.foo.bar/xyz/gnmi-set -
cert_gnoi_timewithspiffe://test-abc.foo.bar/xyz/gnoi-time -
cert_gnoi_pingwithspiffe://test-abc.foo.bar/xyz/gnoi-ping -
cert_gnsi_probewithspiffe://test-abc.foo.bar/xyz/gnsi-probe -
cert_read_onlywithspiffe://test-abc.foo.bar/xyz/read-only
NOTE: unless specifically mentioned, the rule allow-test-infra MUST be attached to all the policies, so that the test or the test infra is not blocked from the device.
{
"name": "allow-test-infra",
"source": {
"principals": [
"<test_infra_id>"
]
},
"request": {}
},Prepare the following gRPC authorization policies.
{
"name": "policy-everyone-can-gnmi-not-gribi",
"allow_rules": [
{
"name": "everyone-can-gnmi-get",
"source": {},
"request": {
"paths": [
"/gnmi.gNMI/Get"
]
}
}
],
"deny_rules": [
{
"name": "no-one-can-gribi-get",
"request": {
"paths": [
"/gribi.gRIBI/Get"
]
}
}
]
} {
"name": "policy-everyone-can-gribi-not-gnmi",
"allow_rules": [
{
"name": "everyone-can-gribi",
"source": {
"principals": [
"*"
]
},
"request": {
"paths": [
"/gribi.gRIBI/*"
]
}
}
],
"deny_rules": [
{
"name": "no-one-can-gnmi",
"source": {
"principals": [
"*"
]
},
"request": {
"paths": [
"/gribi.gNMI/*"
]
}
}
]
}{
"name": "policy-invalid-no-allow-rules",
"deny_rules": [
{
"name": "no-one-can-gribi",
"request": {
"paths": [
"/gribi.gRIBI/*"
]
}
}
]
}{
"name": "policy-gribi-get",
"allow_rules": [
{
"name": "gribi-get",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/read-only"
]
},
"request": {
"paths": ["/gribi.gRIBI/Get"]
}
}
]
}{
"name": "policy-gnmi-get",
"allow_rules": [
{
"name": "gnmi-get",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/read-only"
]
},
"request": {
"paths": ["/gnmi.gNMI/Get"]
}
}
]
}The following table describes policy policy-normal-1:
| Cert | gRIBI.Modify | gRIBI.Get | gNMI.Set | gNMI.Get | gNOI.Time | gNOI.Ping | gNSI.Rotate | gNSI.Get | gNSI.Probe |
|---|---|---|---|---|---|---|---|---|---|
| cert_user_admin | allow | allow | allow | allow | allow | allow | allow | allow | allow |
| cert_user_deny_all | deny | deny | deny | deny | deny | deny | deny | deny | deny |
| cert_gribi_modify | allow | allow | deny | deny | deny | deny | deny | deny | deny |
| cert_gnmi_set | deny | deny | allow | allow | deny | deny | deny | deny | deny |
| cert_gnoi_time | deny | deny | deny | deny | allow | deny | deny | deny | deny |
| cert_gnoi_ping | deny | deny | deny | deny | deny | allow | deny | deny | deny |
| cert_gnsi_probe | deny | deny | deny | deny | deny | deny | deny | deny | allow |
| cert_read_only | deny | allow | deny | allow | deny | deny | deny | allow | deny |
{
"name": "policy-normal-1",
"allow_rules": [
{
"name": "gribi-modify",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/admin",
"spiffe://test-abc.foo.bar/xyz/gribi-modify"
]
},
"request": {
"paths": ["/gribi.gRIBI/*"]
}
},
{
"name": "gnmi-set",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/admin",
"spiffe://test-abc.foo.bar/xyz/gnmi-set"
]
},
"request": {
"paths": ["/gnmi.gNMI/*"]
}
},
{
"name": "gnoi-time",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/admin",
"spiffe://test-abc.foo.bar/xyz/gnoi-time"
]
},
"request": {
"paths": ["/gnoi.system.System/Time"]
}
},
{
"name": "gnoi-ping",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/admin",
"spiffe://test-abc.foo.bar/xyz/gnoi-ping"
]
},
"request": {
"paths": ["/gnoi.system.System/Ping"]
}
},
{
"name": "gnsi-set",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/admin"
]
},
"request": {
"paths": ["/gnsi.authz.v1.Authz/*"]
}
},
{
"name": "gnsi-probe",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/gnsi-probe"
]
},
"request": {
"paths": ["/gnsi.authz.v1.Authz/Probe"]
}
},
{
"name": "read-only",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/read-only"
]
},
"request": {
"paths": [
"/gnmi.gNMI/Get",
"/gribi.gRIBI/Get",
"/gnsi.authz.v1.Authz/Get"
]
}
}
],
"deny_rules": [
{
"name": "deny-all-user-can-do-nothing",
"source": {
"principals": [
"spiffe://test-abc.foo.bar/xyz/deny_all"
]
},
"request": {
"paths": ["/*"]
}
}
]
}NOTE: regarding gNMI OC validation:
- Everytime a gRPC call (including gNSI calls themselves) is allowed or denied, the following OC leaves should be validated:
-
/system/grpc-servers/grpc-server/authz-policy-counters/rpcs/rpc[name]/state/nameis the matched request path, e.g. "/gribi.gRIBI/Get" -
/system/grpc-servers/grpc-server/authz-policy-counters/rpcs/rpc/rpc[name]/state/access-acceptsincrements if the rpc call is allowed. -
/system/grpc-servers/grpc-server/authz-policy-counters/rpcs/rpc/rpc[name]/state/access-rejectsincrements if the rpc call is denied. -
/system/grpc-servers/grpc-server/authz-policy-counters/rpcs/rpc/rpc[name]/state/last-access-acceptreflects the timestamp of the method call. -
/system/grpc-servers/grpc-server/authz-policy-counters/rpcs/rpc/rpc[name]/state/last-access-rejectreflects the timestamp of the method call.
-
- Everytime a valid policy is pushed (even it's not finalized), the following OC leaves should be validated:
-
/system/grpc-servers/grpc-server/state/authz-policy-version=UploadRequest.versionin the API proto. -
/system/grpc-servers/grpc-server/state/authz-policy-created-on=UploadRequest.created_on(in terms of represented time).
-
- Everytime a valid policy is automatically rolled back, the following OC leaves should be validated:
-
/system/grpc-servers/grpc-server/state/authz-policy-version=UploadRequest.versionof the previous request (the one rollback to). -
/system/grpc-servers/grpc-server/state/authz-policy-created-on=UploadRequest.created_onof the previous request (the one rollback to).
-
- An invalid policy should not trigger the following OC leaf updates:
/system/grpc-servers/grpc-server/state/authz-policy-version/system/grpc-servers/grpc-server/state/authz-policy-created-on
For each of the scenarios in this section, we need to exercise the following 3 actions to get the authorization results:
-
gNSI.ProbeafterUploadResponsemessage but before theFinalizeRequestmessage. -
gNSI.Probeafter theRotateAuthzRequestcall finished. -
The actual corresponding service client calls, after the
RotateAuthzRequestcall finished. -
Authz-1.1, "Test empty source"
- Use
gNSI.Rotatemethod to push policypolicy-everyone-can-gnmi-not-gribi, withcreate_on=100andversion=policy-everyone-can-gnmi-not-gribi_v1. - Ensure all results match per the following:
-
cert_user_adminis allowed to issuegNMI.Getmethod. -
cert_user_adminis denied to issuegRIBI.Getmethod.
-
- Use
-
Authz-1.2, "Test empty request"
- Use
gNSI.Rotatemethod to push and finalize policypolicy-everyone-can-gribi-not-gnmi, withcreate_on=100andversion=policy-everyone-can-gribi-not-gnmi_v1. - Ensure all results match per the following:
-
cert_user_deny_allis denied to issuegNMI.Getmethod. -
cert_user_adminis allowed to issuegRIBI.Getmethod.
-
- Use
-
Authz-1.3, "Test that there can only be one policy"
- Use
gNSI.Rotatemethod to push and finalize policypolicy-gribi-get, withcreate_on=100andversion=policy-gribi-get_v1. - Ensure all results match per the following:
-
cert_read_onlyis allowed to issuegRIBI.Getmethod. -
cert_read_onlyis denied to issuegNMI.Getmethod.
-
- Use
gNSI.Rotatemethod to push and finalize policypolicy-gnmi-get. - Ensure all results changed to the following:
-
cert_read_onlyis denied to issuegRIBI.Getmethod. -
cert_read_onlyis allowed to issuegNMI.Getmethod.
-
- Use
-
Authz-1.4, "Test normal policy"
- Use
gNSI.Rotatemethod to push and finalize policypolicy-normal-1, withcreate_on=100andversion=policy-normal-1_v1. - Ensure all results match per the above table for policy
policy-normal-1.
- Use
-
TODO: Authz-1.5, "Test principle prefix and suffix match"
- Test the behavior of prefix and suffix match on principles
-
Authz-2.1, "Test only one rotation request at a time"
- Use
gNSI.Rotatemethod to push policypolicy-everyone-can-gnmi-not-gribi, but don't finalize it yet. - Initial another
gNSI.Rotatemethod to push policypolicy-everyone-can-gribi-not-gnmi, and expect to receive anUNAVAILABLEgRPC error. - Ensure all actual client authorization result stays as per the following:
-
cert_user_adminis allowed to issuegNMI.Getmethod. -
cert_user_adminis denied to issuegRIBI.Getmethod.
-
- Use
-
Authz-2.2, "Test rollback when connection closed"
- Use
gNSI.Rotatemethod to push and finalize policypolicy-gribi-get. - Ensure
gNSI.Proberesult matches the following:-
cert_read_onlyis allowed to issuegRIBI.Getmethod. -
cert_read_onlyis denied to issuegNMI.Getmethod.
-
- Use
gNSI.Rotatemethod to push policypolicy-gnmi-get, but don't finalize it yet. - Ensure
gNSI.Proberesult matches the following:-
cert_read_onlyis denied to issuegRIBI.Getmethod. -
cert_read_onlyis allowed to issuegNMI.Getmethod.
-
- Close the gRPC session.
- Ensure
gNSI.Proberesult changed back to the following:-
cert_read_onlyis allowed to issuegRIBI.Getmethod. -
cert_read_onlyis denied to issuegNMI.Getmethod.
-
- Use
-
Authz-2.3, "Test rollback on invalid policy"
- Use
gNSI.Rotatemethod to push and finalize policypolicy-gribi-get. - Ensure
gNSI.Proberesult matches the following:-
cert_read_onlyis allowed to issuegRIBI.Getmethod. -
cert_read_onlyis denied to issuegNMI.Getmethod.
-
- Use
gNSI.Rotatemethod to push policypolicy-invalid-no-allow-rules, expect an error message and closed gRPC session. - Ensure
gNSI.Proberesult remains as the following:-
cert_read_onlyis allowed to issuegRIBI.Getmethod. -
cert_read_onlyis denied to issuegNMI.Getmethod.
-
- Use
-
Authz-2.4, "Test force_overwrite when the version does not change"
- Use
gNSI.Rotatemethod to push and finalize policypolicy-gribi-get. - Use
gNSI.Rotatemethod to try to push policypolicy-gnmi-getwith version value not changed. Expect error message and closed gRPC session. - Validate that actual client authorization result stays as the following:
-
cert_read_onlyis allowed to issuegRIBI.Getmethod. -
cert_read_onlyis denied to issuegNMI.Getmethod.
-
- Use
gNSI.Rotatemethod to try to push policypolicy-gnmi-getwith version value, butforce_overwriteset to true. Expect no error message, and the push can be finalized. - Ensure actual client authorization results are changed to the following:
-
cert_read_onlyis denied to issuegRIBI.Getmethod. -
cert_read_onlyis allowed to issuegNMI.Getmethod.
-
- Use
- Use
gNSI.Rotatemethod to push and finalize policypolicy-gribi-get. - Wait for 30s, intial
gNSI.Getand validate the value ofversion,created_onand gRPC policy content does not change.
- Use
gNSI.Rotatemethod to push and finalize policypolicy-normal-1. - Reboot the device.
- Reconnect to the device, issue
gNSI.GetandgNMI.Getand validate the value ofversion,created_onand gRPC policy content does not change. - Ensure actual corresponding clients are authorized per the the above table for policy
policy-normal-1.
{
"system": {
"aaa": {
"authentication": {
"users": {
"user": [
{
"config": {
"password": "xxxxxxx",
"ssh-key": "yyyyyyy",
"username": "testuser"
},
"username": "testuser"
}
]
}
}
}
}
}TODO(OCRPC): Record is not complete
The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here.
paths:
###Config paths###
/system/aaa/authentication/users/user/config:
/system/aaa/authentication/users/user/config/username:
/system/aaa/authentication/users/user/config/password:
###State paths###
/system/aaa/authentication/users/user/state:
/system/aaa/authentication/users/user/state/username:
/system/aaa/authentication/users/user/state/password:
/system/aaa/authentication/users/user/state/authorized-principals-list-version:
/system/aaa/authentication/users/user/state/authorized-principals-list-created-on:
rpcs:
gnsi:
credentialz.v1.Credentialz.RotateAccountCredentials:
- KNE