cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
528
Views
1
Helpful
2
Replies
Highlighted
Beginner

Filter Incoming Request

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

1 ACCEPTED SOLUTION

Accepted Solutions
Highlighted
Cisco Employee

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

View solution in original post

2 REPLIES 2
Highlighted
Cisco Employee

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

View solution in original post

Highlighted

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.