Skip to content

Latest commit

 

History

History

linkerd_authz

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

Micro-service Authorization with Linkerd

An experimental, policy-enabled, linkerd identifier that enforces authorization decisions.

Building

./sbt assembly  # puts JAR under target/scala-2.11/

Running (local)

Download and untar linkerd-0.9.0, change into directory.

  1. export L5D_HOME=$PWD sets environment variable that linkerd-0.9.0-exec script uses to load plugins.

  2. mkdir -p plugins creates directory to stick plugin JARs into.

  3. Copy JAR file into plugins directory.

  4. Create linkerd configuration at config/opa_linkerd_example.yaml:

    namers:
    - kind: io.l5d.fs
    rootDir: disco
    
    routers:
    - protocol: http
    dtab: |
      /dns-hostport => /$/inet;
      /dns          => /$/io.buoyant.hostportPfx/dns-hostport | /$/inet;
      /pool         => /#/io.l5d.fs;
      /svc          => /pool | /dns;
    httpAccessLog: /dev/stdout
    identifier:
      kind: org.openpolicyagent.linkerd.authzIdentifier
      ip: 127.0.0.1
      port: 8181
      path: /v1/data/example/linkerd/authz
    servers:
      - port: 4140
        ip: 0.0.0.0
        addForwardedHeader:
          by:
            kind: "ip:port"
          for:
            kind: "ip"
  5. Run linkerd:

    ./linkerd-0.9.0-exec config/opa_linkerd_example.yaml

Manual Testing (local)

  1. Start a simple webserver:

    python -m SimpleHTTPServer 9999
  2. Start OPA:

    docker run -p 8181:8181 openpolicyagent/opa:0.4.6 run --server --log-level=debug
  3. Define simple policy (example.rego):

    package example.linkerd.authz
    
    import input.method
    import input.path
    
    errors["request denied by administrative policy"] {
      not allow
    }
    
    default allow = false
    
    allow {
      method = "GET"
      not contains(path, "deadbeef")
    }
  4. Push policy into OPA:

    curl -X PUT localhost:8181/v1/policies/test --data-binary @example.rego

    and then, optionally, watch the policy for changes and push into OPA:

    fswatch -o example.rego | xargs -n1 \
      curl -X PUT localhost:8181/v1/policies/test --data-binary @example.rego
    
  5. GET some document from webserver via linkerd:

    curl -H 'Host: web' localhost:4140
  6. Try to POST some document to webserver via linkerd:

    curl -d 'hooray' -H 'Host: web' localhost:4140

    Response:

    Unknown destination: Request("POST /", from /127.0.0.1:59508) / request denied by administrative policy
    

That's it! 🎉

More Information and Future Work

By default, the identifier is designed to fail-closed. This means that if an error occurs while communicating with OPA or OPA returns an error, the identifier will deny the request.

The identifier is currently hard-coded to use the io.buoyant.router.http.HeaderIdentifier as the actual underlying identifier. The Host header is used as input to the HeaderIdentifier.

Future work could include:

  • Separating the authorization and identification steps so that underlying identifiers do not have to be wrapped.
  • Adding support for sending the entire HTTP message body to OPA (in addition to headers, path, and method).
  • Adding support for protocols other than HTTP.