12-15-2017 09:34 PM - edited 03-01-2019 04:04 AM
Hi Cisco,
We implemented a role based authentication in NSO. The request which comes from north bound should not allowed to delete all services.
Not Allowed :
Method : Delete
URL : http://******.com:8080/api/running/services
Function : This request deletes all the services in NSO
Allowed :
Method : Delete
URL : http://******.com:8080/api/running/services/l2/service-id
Function : This deletes only the particular service
We tried to achieve the above using NACM rules. But we couldn't achieve that and we got to know that NSO doesn't support this feature based on the URL.
I would like to know is it possible to write a package or a wrapper class to filter/intercepting the incoming request and make decision based on our requirements. I'm expecting to write basic web filtering. How can i achieve this in NSO ?
If we can do this, could you please share us a code snippet for accessing the Session and User Info.
If this is not possible we are open for any ideas to achieve the same.
Advance thanks
Solved! Go to Solution.
12-17-2017 08:07 PM
Hello Equinix ENPS Team,
Unfortunately, I don't think NACM at the current release can achieve what you requested.
Instead, there are a couple of possible alternatives:
1. Add a flag to package and check it before delete
2. Use reverse proxy such as Nginx
The first solution is add a flag and use preModification callback to check it.
A smaple code is as follows.
[YANG]
leaf active {
type boolean;
default true;
}
[Python]
import ncs.maagic as maagic
@Service.pre_modification
def cb_pre_modification(self, tctx, op, kp, root, proplist):
self.log.info('Service premod(service=', kp, ')')
if op == 2: # check only on delete (0=create, 1=modify, 2=delete)
self.log.info("delete operation")
with ncs.maapi.single_read_trans("admin", "system") as t:
root = ncs.maagic.get_root(t)
service = ncs.maagic.cd(root, kp)
# get the flag
if service.active:
raise ValueError("Operation failed: "+service.name+" is still active")
[Sample outputs]
There are two service instances.
admin@ncs# show running-config services
services blockDelAll test1
dummy-value aaa
!
services blockDelAll test2
dummy-value bbb
Send a REST command to delete "services" is blocked as follows.
$ curl -u admin:admin http://127.0.0.1:8080/api/running/services -X DELETE
<errors xmlns="http://tail-f.com/ns/tailf-rest-error">
<error>
<error-tag>malformed-message</error-tag>
<error-message>Python cb_pre_modification error. Operation failed: test1 is still active</error-message>
</error>
</errors>
To delete the service instance, user must disable the instance first.
$ cat deactivate.xml
<blockDelAll>
<name>test1</name>
<active>false</active>
</blockDelAll>
$ curl -u admin:admin http://127.0.0.1:8080/api/running/services/blockDelAll -T deactivate.xml -X PATCH
$ curl -u admin:admin http://127.0.0.1:8080/api/running/services/blockDelAll/test1 -X DELETE
This is more secure, but need redundant steps.
The oter way is to use a reverse proxy, such as Nginx.
A sample configuration would be something like follows.
[NGINX]
events {
worker_connections 1024;
}
http {
server {
listen 9000;
server_name localhost;
location /api/running/services/bgpmgr {
# Allows specific URL to delete
proxy_pass http://127.0.0.1:8080/api/running/services/bgpmgr;
}
location / {
limit_except GET {
deny all;
}
# NSO URL only allow GET
proxy_pass http://127.0.0.1:8080/;
}
}
}
In this case, user cannot delete /services, but allowed to delete a specific path.
[Sample GET]
cisco@debian:~/nginx$ curl -u admin:admin http://127.0.0.1:9000/api/running/services/bgpmgr
<collection xmlns:y="http://tail-f.com/ns/rest">
<bgpmgr xmlns="http://example.com/bgpmgr">
<name>R1R2</name>
<dev1>R1</dev1>
<dev1-loop>1.1.1.1</dev1-loop>
<dev1-as>65001</dev1-as>
<dev1-addr>10.12.0.1</dev1-addr>
<dev2>R2</dev2>
<dev2-loop>2.2.2.2</dev2-loop>
<dev2-as>65002</dev2-as>
<dev2-addr>10.12.0.2</dev2-addr>
<y:operations>
<check-sync>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/check-sync</check-sync>
<deep-check-sync>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/deep-check-sync</deep-check-sync>
<re-deploy>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/re-deploy</re-deploy>
<reactive-re-deploy>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/reactive-re-deploy</reactive-re-deploy>
<touch>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/touch</touch>
<get-modifications>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/get-modifications</get-modifications>
<un-deploy>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/un-deploy</un-deploy>
</y:operations>
</bgpmgr>
</collection>
[DELETE /services] - forbidden
cisco@debian:~/nginx$ curl -u admin:admin http://127.0.0.1:9000/api/running/services -X DELETE
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.6.2</center>
</body>
</html>
[Delete a specific instance] - works
cisco@debian:~/nginx$ curl -u admin:admin http://127.0.0.1:9000/api/running/services/bgpmgr -X DELETE
cisco@debian:~/nginx$
Hope this helps.
Best regards,
Hiro
12-17-2017 08:07 PM
Hello Equinix ENPS Team,
Unfortunately, I don't think NACM at the current release can achieve what you requested.
Instead, there are a couple of possible alternatives:
1. Add a flag to package and check it before delete
2. Use reverse proxy such as Nginx
The first solution is add a flag and use preModification callback to check it.
A smaple code is as follows.
[YANG]
leaf active {
type boolean;
default true;
}
[Python]
import ncs.maagic as maagic
@Service.pre_modification
def cb_pre_modification(self, tctx, op, kp, root, proplist):
self.log.info('Service premod(service=', kp, ')')
if op == 2: # check only on delete (0=create, 1=modify, 2=delete)
self.log.info("delete operation")
with ncs.maapi.single_read_trans("admin", "system") as t:
root = ncs.maagic.get_root(t)
service = ncs.maagic.cd(root, kp)
# get the flag
if service.active:
raise ValueError("Operation failed: "+service.name+" is still active")
[Sample outputs]
There are two service instances.
admin@ncs# show running-config services
services blockDelAll test1
dummy-value aaa
!
services blockDelAll test2
dummy-value bbb
Send a REST command to delete "services" is blocked as follows.
$ curl -u admin:admin http://127.0.0.1:8080/api/running/services -X DELETE
<errors xmlns="http://tail-f.com/ns/tailf-rest-error">
<error>
<error-tag>malformed-message</error-tag>
<error-message>Python cb_pre_modification error. Operation failed: test1 is still active</error-message>
</error>
</errors>
To delete the service instance, user must disable the instance first.
$ cat deactivate.xml
<blockDelAll>
<name>test1</name>
<active>false</active>
</blockDelAll>
$ curl -u admin:admin http://127.0.0.1:8080/api/running/services/blockDelAll -T deactivate.xml -X PATCH
$ curl -u admin:admin http://127.0.0.1:8080/api/running/services/blockDelAll/test1 -X DELETE
This is more secure, but need redundant steps.
The oter way is to use a reverse proxy, such as Nginx.
A sample configuration would be something like follows.
[NGINX]
events {
worker_connections 1024;
}
http {
server {
listen 9000;
server_name localhost;
location /api/running/services/bgpmgr {
# Allows specific URL to delete
proxy_pass http://127.0.0.1:8080/api/running/services/bgpmgr;
}
location / {
limit_except GET {
deny all;
}
# NSO URL only allow GET
proxy_pass http://127.0.0.1:8080/;
}
}
}
In this case, user cannot delete /services, but allowed to delete a specific path.
[Sample GET]
cisco@debian:~/nginx$ curl -u admin:admin http://127.0.0.1:9000/api/running/services/bgpmgr
<collection xmlns:y="http://tail-f.com/ns/rest">
<bgpmgr xmlns="http://example.com/bgpmgr">
<name>R1R2</name>
<dev1>R1</dev1>
<dev1-loop>1.1.1.1</dev1-loop>
<dev1-as>65001</dev1-as>
<dev1-addr>10.12.0.1</dev1-addr>
<dev2>R2</dev2>
<dev2-loop>2.2.2.2</dev2-loop>
<dev2-as>65002</dev2-as>
<dev2-addr>10.12.0.2</dev2-addr>
<y:operations>
<check-sync>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/check-sync</check-sync>
<deep-check-sync>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/deep-check-sync</deep-check-sync>
<re-deploy>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/re-deploy</re-deploy>
<reactive-re-deploy>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/reactive-re-deploy</reactive-re-deploy>
<touch>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/touch</touch>
<get-modifications>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/get-modifications</get-modifications>
<un-deploy>/api/running/services/bgpmgr:bgpmgr/R1R2/_operations/un-deploy</un-deploy>
</y:operations>
</bgpmgr>
</collection>
[DELETE /services] - forbidden
cisco@debian:~/nginx$ curl -u admin:admin http://127.0.0.1:9000/api/running/services -X DELETE
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.6.2</center>
</body>
</html>
[Delete a specific instance] - works
cisco@debian:~/nginx$ curl -u admin:admin http://127.0.0.1:9000/api/running/services/bgpmgr -X DELETE
cisco@debian:~/nginx$
Hope this helps.
Best regards,
Hiro
12-18-2017 01:36 AM
I don't think NACM will ever do exactly the kind of thing you're looking for. NACM is about specifying rules for which operators/roles that have access to create, read, update, delete or execute a certain piece of information/action. It is specifically staying away from listing the exact method used for the access, since NACM applies to CLI, Web, NETCONF, RESTCONF etc, and their exact access method details vary.
So if you want an operator to have access to delete any service instance, NACM rules will not differentiate between deleting one or all instances.
What you could do, potentially, is to ensure you always have one particular service instance that nobody is allowed to delete. Any attempt to delete all will then fail because there is one that can't be deleted.
Finally a note about the NGINX approach above. This probably works well for the DELETE operation over RESTCONF. It would still allow an operator to accidentally/intentionally delete all instances by use of PUT or PATCH. And it would not apply to other management protocols than RESTCONF, such as the NSO CLI or NETCONF.
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide