Grid : dCache: Macaroons for reading/writing files

(copied from the Scientific Computing internal documentation as of 2019.Jul.29)

Idea

Request a read-only macaroon for a specific ntuple and use it to stream-read in ROOT

curl parameters

For the following examples we use curl, where the following options are handy

  • -L / --location: let curl follow redirects, which is needed when we talk to a WebDAV door as entrypoint and the door wants to redirect our request to the dCache pool for the actual file location
  • --fail, --include: in case of an error, --fail will just print a one-line message instead of dumping the full server http-error page; on the other hand --include will we more verbose and dump also the full header
  • --capath: path where the CA root certificates for the host certs are
  • --cacert, --cert, --key: path to the certificate&key for authz - in the grid world these are your grid user proxy

when using another tool/library, you probably need to check for the equivalent options

Depending on the tool/library, exporting the CA path might be picked up with something like

export X509_CERT_DIR=/cvmfs/grid.cern.ch/etc/grid-security/certificates

Basic macaroon handling

Basic request to get a full-power Macaroon with a valid Grid proxy
> curl [--include,--fail] -L --key $X509_USER_PROXY  --cert $X509_USER_PROXY  --cacert $X509_USER_PROXY  --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' https://dcache-se-doma.desy.de:2880
HTTP/1.1 200 OK
Date: Mon, 29 Jul 2019 10:04:38 GMT
Server: dCache/5.2.1
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PROPFIND
Access-Control-Allow-Headers: Content-Type, Authorization
Content-Length: 1082

{
"macaroon": "MDAxY2xvY2F0...",
"uri": {
"targetWithMacaroon": "https://dcache-se-doma.desy.de:2880/?authz=MDAxY2xvY2F0aW9uIE9wd....",
"baseWithMacaroon": "https://dcache-se-doma.desy.de:2880/?authz=MDAxY2xvY2F0....",
"target": "https://dcache-se-doma.desy.de:2880/",
"base": "https://dcache-se-doma.desy.de:2880/"
}
}
Macaroon limited to list and download from a specific directory, valid for 1 day and 12 hours
> curl [--include,--fail] -L --key $X509_USER_PROXY  --cert $X509_USER_PROXY  --cacert $X509_USER_PROXY  --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/  -X POST  -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read 
HTTP/1.1 200 OK
Date: Mon, 29 Jul 2019 10:23:02 GMT
Server: dCache/5.2.1
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PROPFIND
Access-Control-Allow-Headers: Content-Type, Authorization
Content-Length: 1534

{
    "macaroon": "MDAzNWxvY2F0aW9u...",
    "uri": {
        "targetWithMacaroon": "https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read?authz=MDAzNWxvY2F0aW9uIE9wdG....",
        "baseWithMacaroon": "https://dcache-se-doma.desy.de:2880/?authz=MDAzNWxvY2F0aW9uIE9wdGlv....",
        "target": "https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read",
        "base": "https://dcache-se-doma.desy.de:2880/"
    }
}


see the ISO 8601 documentation for the date/period formatting.


The same using Python requests library:

This comes from dcache event demo and is hardwired against dcache-xdc.desy.de. It uses basic auth, but could use x509 or a management macaroon as well.


download macaroon
    def get_download_link(self, path, time = "PT1H"):
        if path.startswith("https://dcache-xdc.desy.de/"):
            path = path[len("https://dcache-xdc.desy.de/"):]
        api = "https://{}:{}@dcache-xdc.desy.de/".format(self.dcache_user, self.dcache_password)
        headers = {"Content-Type": "application/macaroon-request"}
        data = {"caveats": ["activity:DOWNLOAD", "path:" + path],
               "validity":time} 
        res = post(api, headers = headers, data = json.dumps(data))   
        macaroon = json.loads(res.content.decode("ascii"))["macaroon"]
        return "https://dcache-xdc.desy.de/{}?authz={}".format(path,macaroon)         

Listing & Reading

first, we try to read it with our proxy and pipe the result through xmllint for a more readable structure

> curl [--include,--fail] -L --key $X509_USER_PROXY --cert $X509_USER_PROXY --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X PROPFIND -H "Depth: 1" https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read | xmllint --format -

Now we try without the macaroon and without the proxy

> curl [--include,--fail] -L --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X PROPFIND -H "Depth: 1" https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read

the result should be empty.

Finally we try to list the directory and read the file it without the proxy but with our macaroon

>

> curl [--include,--fail] -L --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X PROPFIND -H "Depth: 1" -H "Authorization: Bearer MDAzNWxvY2F0a...." https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read/read_txt.rnd | xmllint --format -

> MACAROON=MDAzNWxvY2F0a.... # exporting the macaroon into an environment variable to make life easier

> curl [--include,--fail] -L --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X GET -H "Authorization: Bearer $MACAROON" https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read/read_txt.rnd --location --output /tmp/foo.foo

note, that we had to give the two header fields for the listing depth and the macaroon separately and could not combine them in one header field

Changing root dir

with the 'root' caveat, the base path can be limited to a subtree

> curl [--include,--fail] -L --key /tmp/x509up_u26551 --cert /tmp/x509up_u26551 --cacert /tmp/x509up_u26551 --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST","root:/desy/Hamburg/MacaroonIO/"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/

> curl [--include,--fail] -L--capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X PROPFIND -H "Depth: 1" -H "Authorization: Bearer $MACAROON" https://dcache-se-doma.desy.de:2880/ | xmllint --format -

where dCache will return under nominally '/' now only the content under /desy/Hamburg/MacaroonIO/

Limiting the path

Similarly the 'path' limits a Macaroon just to one specific path, i.e., only the given file/path will be available with

> curl [--include,--fail] -L --key /tmp/x509up_u26551 --cert /tmp/x509up_u26551 --cacert /tmp/x509up_u26551 --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST","path:/desy/Hamburg/MacaroonIO/read/read_txt.rnd"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880

or


> curl [--include,--fail] -L --key /tmp/x509up_u26551 --cert /tmp/x509up_u26551 --cacert /tmp/x509up_u26551 --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read/read_txt.rnd

note, that a path limitation should betetr only be given once, i.e., in the URL (as short-cut) or in the header caveat field, since both are interpreted as caveats. When giving both, as full path URL and path caveat, both are applied and you would end up with to caveat, that might compete and break the Macaroon for you.

IP

Limit the IP range to the DESY subnet with the IP caveat

"caveats": ["ip:2001:638:700::/48","ip:131.169.0.0/16"]

Writing

for writing, request an upload macaroon, with which we can put a file under the path

> curl [--include,--fail] -L --key $X509_USER_PROXY --cert $X509_USER_PROXY --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:UPLOAD"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/write

> curl --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -T /tmp/BXMuMu.root  -H "Authorization: Bearer ${MACAROON}" https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/write/


Mkdir

Similarly, a new directory can be created with the MANAGE activity

> curl [--include,--fail] -L --key $X509_USER_PROXY --cert $X509_USER_PROXY --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:MANAGE,LIST"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/write

> curl --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X MKCOL https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/write/new.d -H "Authorization: Bearer ${MACAROON}"

Deletion

A macaroon with a DELETION activity can delete a path with -X DELETE .


ROOT Example

Simple root example for Macaroon I/O (at least input via macaroons as I have not managed to let ROOT write to a remote URL in a specific format over http...)

export X509_CERT_DIR=/cvmfs/grid.cern.ch/etc/grid-security/certificates
export INMACAROON="https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read/BXMuMu.root?authz=MDA0MWxvY..."
export OUTMACAROON="/tmp/macaroonio_out.png"

macaroonio.C
#include "TH1.h"
#include "TList.h"
#include "TCanvas.h"
#include "TStyle.h"
#include "TSystem.h"

void macaroonio() {
  const char * INMACAROON = gSystem->Getenv("INMACAROON");
  const char * OUTMACAROON = gSystem->Getenv("OUTMACAROON");
  TFile *inFile = TFile::Open(INMACAROON);
  TH1D *h1 = new TH1D("h1","Hello Macaroon",200,5000,7000);
  TCanvas * c1 = new TCanvas("c1", "c1", 900, 600);
  c1->cd();
  TObject * inTree = inFile->Get("DecayTree");
  inTree->Draw("Bplus_MM>>h1");
  c1->SaveAs(OUTMACAROON);
}



Links

Attachments:

paul4.pdf (application/pdf)