Assertions Service on staging

Matt Goodall matt.goodall at canonical.com
Fri Feb 26 00:21:12 UTC 2016


Hi all,

Thanks to the hard work of Caio Begotti, an initial version of the Snap
Assertions Service (SAS) is available at:

    https://assertions.staging.ubuntu.com/

There's two parts to it: a signing service and a database of assertions.

The signing service is used only to sign new assertions as the "canonical"
authority and so is probably most interesting to other, internal services.
For now, you must be connected to the Canonical VPN to access this part.

The database part provides a simple API to add, find, and search
assertions. The database promises that its assertions are consistent with
each other, but nothing more.

I've attached the API documentation. You'll also need to refer to the
Snappy System Design document for information about specific assertion
types.

The service currently supports the following assertion types, with
`identity` hopefully landing soon.

    - account-key
    - device
    - model
    - snap-build
    - snap-revision

The only major API change we're *expecting* is to add authentication. It's
quite likely that all requests will require authentication as either a
device, user, or trusted service, most likely using macaroons with a
discharge from one of the identity services.

Warning: right now, the assertions are stored on the unit's file system.
We'll try to upgrade nicely and keep the database intact, but please try
not to get too angry if everything disappears ;-).

There's still plenty to do - proper database backend, authentication, the
occasional bug fix ;) - but please have a read/play and let us know what
you think.

Cheers,
Matt (atomatt)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ubuntu.com/archives/snappy-devel/attachments/20160226/ceccca72/attachment.html>
-------------- next part --------------
Assertions Service HTTP API
===========================

The Assertions Service ("the service" from now on) manages a database of
assertions and provides an HTTP API to sign, add, find, etc assertions.


Response Format
---------------

The service is primarily a JSON service. All request and response bodies are
therefore `application/json` unless noted otherwise.


Errors
------

The service uses conventional HTTP response codes to indicate success or
failure of an API request. In general, codes in the 2xx range indicate success,
codes in the 4xx range indicate an error that resulted from the provided
information (e.g. a required parameter was missing) and codes in the 5xx range
indicate an error with our servers.

Note that some 5xx errors, specifically 503 Service Unavailable, indicate a
temporary server error. The operation may succeed if the client retries the
request after a short delay.

Error responses will be structured according to "Problem Details for HTTP
APIs", https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-03, e.g.:

    {
        // HTTP response code.
        "status": 400,

        // Error type identifier (for machines).
        "type": "assertions:v1:invalid-assertion",

        // Human readable description of the error type.
        "title": "invalid assertion",

        // Optional full, human readable explanation of the error.
        "detail": "the assertion's signature is invalid"
    }

If the error's `type` is not specific enough to drive the behaviour of a
client, e.g.  to inform the user of the source of the problem or handle the
error condition correctly, please ask the developers to define a new type.


### assertion refused

* Type - assertions:v1:assertion-refused
* Status - 400 Bad Request

The assertion is formatted correctly but failed signature validation or
consistency checks.


### invalid request

* Type - assertions:v1:invalid-request
* Status - 400 Bad Request

The request from the client is invalid, e.g. an incorrect path, missing body,
incorrect headers, etc.


### invalid assertion

* Type - assertions:v1:invalid-assertion
* Status - 400 Bad Request

The assertion has an invalid format, e.g. it cannot be parsed or contains
invalid data.


### not found

* Type - assertions:v1:not-found
* Status - 404 Not Found

The requested item could not be found.


### unsupported media type

* Type - assertions:v1:unsupported-media-type
* Status - 415 Unsupported Media Type

The request's Accept or Content-Type header is not recognised by the resource.


POST /v1/sign - construct and sign assertion
--------------------------------------------

Construct an assertion from data in the request body and sign it using the key
belonging to the entity identified by the assertion's `authority-id` header.

The resulting assertion is not added to the database. It will be valid at the
time of signing but not necessarily consistent with existing assertions in the
database.

    POST /v1/sign
    Content-Type: application/json

    {
        "key-id": "0123456789abcdef",
        "headers": {
            "type": "account-key",
            "authority-id": "canonical",
            "account-id": "whoever",
            "public-key-id": "abcdef0123456789",
            ...
        },
        "content": "openpgp content..."
    }

The `key-id` must uniquely identify a valid key for the signing authority in
the assertions's `authority-id` header.

Returns an assertion signed by the authority's key:

    HTTP/1.1 200 OK
    Content-Type: application/x.ubuntu.assertion

    type: account-key
    authority-id: canonical
    account-id: whoever
    public-key-id: abcdef0123456789
    ...

    openpgp content...

    openpgp signature...


POST /v1/assertions?check-only - check and validate assertion
-------------------------------------------------------------

Check an assertion is correctly formatted, signed, and consistent with the set
of assertions currently stored in the database.

    POST /v1/assertions?check-only
    Content-Type: application/x.ubuntu.assertion

    type: account-key
    authority-id: canonical
    account-id: whoever
    public-key-id: abcdef0123456789
    ...

    openpgp content...

    openpgp signature...

Returns a summary of the assertion.

    HTTP/1.1 200 OK
    Content-Type: application/json

    {
        "headers": {
            "type": "account-key",
            "authority-id": "canonical",
            "account-id": "whoever",
            "public-key-id": "abcdef0123456789",
            ...
        }
    }


POST /v1/assertions - add assertion to database
-----------------------------------------------

Add an assertion to the database, performing consistency checks as necessary.

    POST /v1/assertions
    Content-Type: application/x.ubuntu.assertion

    type: account-key
    authority-id: canonical
    account-id: whoever
    public-key-id: abcdef0123456789
    ...

    openpgp content...

    openpgp signature...

Returns a summary of the assertion just added.

    HTTP/1.1 201 Created
    Content-Type: application/json

    {
        "headers": {
            "type": "account-key",
            "authority-id": "canonical",
            "account-id": "whoever",
            "public-key-id": "abcdef0123456789",
            ...
        }
    }


GET /v1/assertions/:type/*key - find an assertion
-------------------------------------------------

Retrieve the latest revision of an assertion by type and key.

The type must be a known assertion type. The key is made up of the primary key
values for the assertion and joined with a slash (/) delimeter.

By default (or with an explicit `Accept: application/json` header) a JSON
summary of the assertion is returned.

    GET /v1/assertions/account-key/whoever/abcdef0123456789
    Accept: application/json

    HTTP/1.1 200 OK
    Content-Type: application/json

    {
        "headers": {
            "type": "account-key",
            "authority-id": "canonical",
            "account-id": "whoever",
            "public-key-id": "abcdef0123456789",
            ...
        }
    }

The original assertion can be retrieved by sending an
`Accept: application.x.ubuntu.assertion` header.

    GET /v1/assertions/account-key/whoever/abcdef0123456789
    Accept: application/x.ubuntu.assertion

    HTTP/1.1 200 OK
    Content-Type: application/x.ubuntu.assertion

    type: account-key
    authority-id: canonical
    account-id: whoever
    public-key-id: abcdef0123456789
    ...

    openpgp content...

    openpgp signature...


GET /v1/assertions/:type - search assertions
--------------------------------------------

Search for assertions of a specific type, optionally filtering by assertion
headers, and return the list of matching assertions.

The type must be a known assertion type. Any query parameters become the header
filter, e.g.

* `/v1/assertions/account-key` - matches all `account-key` assertions.
* `/v1/assertions/account-key?account-id=whoever` - matches any `account-key`
  assertion with an `account-id` equal to "whoever".

By default (or with an explicit `Accept: application/json` header) a JSON
document containing a list of summaries of matching assertions is returned.

    GET /v1/assertions/account-key
    Accept: application/json

    HTTP/1.1 200 OK
    Content-Type: application/json

    {
        "assertions": [
            {
                "headers": {
                    "type": "account-key",
                    "authority-id": "canonical",
                    "account-id": "canonical",
                    "public-key-id": "0123456789abcdef",
                    ...
                }
            },
            {
                "headers": {
                    "type": "account-key",
                    "authority-id": "canonical",
                    "account-id": "atomatt",
                    "public-key-id": "abcdef0123456789",
                    ...
                }
            }
        ]
    }

The original assertions can be retrieved by sending an
`Accept: application.x.ubuntu.assertion` header. The assertions are returned as
a stream, where assertions are separated by a double new line (\n\n) and the
number of assertions is in the X-Ubuntu-Assertions-Count header.

    GET /v1/assertions/account-key
    Accept: application/x.ubuntu.assertion

    HTTP/1.1 200 OK
    Content-Type: application/x.ubuntu.assertion
    X-Ubuntu-Assertions-Count: 2

    type: account-key
    authority-id: canonical
    account-id: canonical
    public-key-id: 0123456789abcdef
    ...

    openpgp content...

    openpgp signature...

    type: account-key
    authority-id: canonical
    account-id: whoever
    public-key-id: abcdef0123456789
    ...

    openpgp content...

    openpgp signature...


More information about the snappy-devel mailing list