deckhand/deckhand/control
Felipe Monteiro 582dee6fb9 DECKHAND-61: oslo.policy integration
This PS implements oslo.policy integration in Deckhand.
The policy.py file implements 2 types of functions for
performing policy enforcement in Deckhand: authorize,
which is a decorator that is used directly around
falcon on_HTTP_VERB methods that raises a 403 immediately
if policy enforcement fails; and conditional_authorize,
to be used inside controller code conditionally.

For example, since Deckhand has two types of documents
with respect to security -- encrypted and cleartext
documents -- policy enforcement is conditioned on the
type of the documents' metadata.storagePolicy.

Included in this PS:
  - policy framework implementation
  - policy in code and policy documentation for all
    Deckhand policies
  - modification of functional test script to override
    default admin-only policies with custom policy file
    dynamically created using lax permissions
  - bug fix for filtering out deleted documents (and
    its predecessors in previous revisions) for
    PUT /revisions/{revision_id}/documents
  - policy documentation
  - basic unit tests for policy enforcement framework
  - allow functional tests to be filtered via regex

Due to the size of this PS, functional tests related to
policy enforcement will be done in a follow up.

Change-Id: If418129f9b401091e098c0bd6c7336b8a5cd2359
2017-10-07 18:43:28 +01:00
..
views DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
README.rst Support filtering revision (documents) by any legal filter 2017-10-06 16:48:45 -04:00
__init__.py DECKHAND-2: Design core Deckhand API framework 2017-06-27 19:26:51 +01:00
api.py DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
base.py DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
buckets.py DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
common.py Support filtering revision (documents) by any legal filter 2017-10-06 16:48:45 -04:00
revision_diffing.py DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
revision_documents.py DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
revision_tags.py DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
revisions.py DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
rollback.py DECKHAND-61: oslo.policy integration 2017-10-07 18:43:28 +01:00
versions.py Clean up Deckhand 405/404 error handling 2017-09-20 14:27:47 -04:00

README.rst

Control

This is the external-facing API service to operate on and query Deckhand-managed data.

v1.0 Endpoints

POST /documents

Accepts a multi-document YAML body and creates a new revision which adds those documents. Updates are detected based on exact match to an existing document of schema + metadata.name. Documents are "deleted" by including documents with the tombstone metadata schema, such as:

`yaml --- schema: any-namespace/AnyKind/v1 metadata: schema: metadata/Tombstone/v1 name: name-to-delete ...`

This endpoint is the only way to add, update, and delete documents. This triggers Deckhand's internal schema validations for all documents.

If no changes are detected, a new revision should not be created. This allows services to periodically re-register their schemas without creating unnecessary revisions.

Sample response:

`yaml --- created_at: '2017-07-31T14:46:46.119853' data: path: to: merge: into: ignored: {data: here} parent: {foo: bar} substitution: {target: null} deleted: false deleted_at: null id: f99630d9-a89c-4aad-9aaa-7c44462047c1 metadata: labels: {genesis: enabled, master: enabled} layeringDefinition: abstract: false actions: - {method: merge, path: .path.to.merge.into.parent} - {method: delete, path: .path.to.delete} layer: region parentSelector: {required_key_a: required_label_a, required_key_b: required_label_b} name: unique-name-given-schema schema: metadata/Document/v1 storagePolicy: cleartext substitutions: - dest: {path: .substitution.target} src: {name: name-of-source-document, path: .source.path, schema: another-service/SourceType/v1} name: unique-name-given-schema revision_id: 0206088a-c9e9-48e1-8725-c9bdac15d6b7 schema: some-service/ResourceType/v1 updated_at: '2017-07-31T14:46:46.119858'`

GET /revisions

Lists existing revisions and reports basic details including a summary of validation status for each deckhand/ValidationPolicy that is part of that revision.

Sample response:

`yaml --- count: 7 next: https://deckhand/api/v1.0/revisions?limit=2&offset=2 prev: null results: - id: 0 url: https://deckhand/api/v1.0/revisions/0 createdAt: 2017-07-14T21:23Z validationPolicies: site-deploy-validation: status: failed - id: 1 url: https://deckhand/api/v1.0/revisions/1 createdAt: 2017-07-16T01:15Z validationPolicies: site-deploy-validation: status: succeeded ...`

GET /revisions/{revision_id}/documents

Returns a multi-document YAML response containing all the documents matching the filters specified via query string parameters. Returned documents will be as originally posted with no substitutions or layering applied.

Supported query string parameters:

  • schema - string, optional - The top-level schema field to select. This may be partially specified by section, e.g., schema=promenade would select all kind and version schemas owned by promenade, or schema=promenade/Node which would select all versions of promenade/Node documents. One may not partially specify the namespace or kind, so schema=promenade/No would not select promenade/Node/v1 documents, and schema=prom would not select promenade documents.
  • metadata.name - string, optional
  • metadata.layeringDefinition.abstract - string, optional - Valid values are the "true" and "false".
  • metadata.layeringDefinition.layer - string, optional - Only return documents from the specified layer.
  • metadata.label - string, optional, repeatable - Uses the format metadata.label=key=value. Repeating this parameter indicates all requested labels must apply (AND not OR).

Sample response:

`yaml created_at: '2017-07-31T14:36:00.352701' data: {foo: bar} deleted: false deleted_at: null id: ffba233a-326b-4eed-9b21-079ebd2a53f0 metadata: labels: {genesis: enabled, master: enabled} layeringDefinition: abstract: false actions: - {method: merge, path: .path.to.merge.into.parent} - {method: delete, path: .path.to.delete} layer: region parentSelector: {required_key_a: required_label_a, required_key_b: required_label_b} name: foo-name-given-schema schema: metadata/Document/v1 storagePolicy: cleartext substitutions: - dest: {path: .substitution.target} src: {name: name-of-source-document, path: .source.path, schema: another-service/SourceType/v1} name: foo-name-given-schema revision_id: d3428d6a-d8c4-4a5b-8006-aba974cc36a2 schema: some-service/ResourceType/v1 updated_at: '2017-07-31T14:36:00.352705'`

Testing

Document creation can be tested locally using (from root deckhand directory):

$ curl -i -X PUT localhost:9000/api/v1.0/bucket/{bucket_name}/documents \
     -H "Content-Type: application/x-yaml" \
     --data-binary "@deckhand/tests/unit/resources/sample_document.yaml"

# revision_id copy/pasted from previous response.
$ curl -i -X GET localhost:9000/api/v1.0/revisions/1