openapi: 3.0.2 info: description: >- This API is meant for provisioning resources in a target Cloud Environment in a vendor-agnostic fashion. By implementing this API, vendors make it possible to automatically provision accounts via ATAT. ## Portfolios Portfolios represent a logical container for a set of cloud resources which are paid for by a Task Order and its CLIN(s). The term is meant to be agnostic across CSPs. A Portfolio can be thought of as an account at the root of a hierarchy. ATAT does not dictate structure within a Portfolio. Once a Portfolio has been provisioned a Mission Owner is free to organize and secure resources to satisfy mission requirements. ## Task Orders Portfolios contain one or more *Task Orders* (TO), which in turn contain or more or *Contract Line Item Number* (CLINs). Each have separate Periods of Performance (PoP) dates; CLIN PoP dates will be within the time frames of the Task Order in which they belong. ## Cost reporting Provisioned resources incur costs with participating CSPs. Costs related to provisioned resources can be attributed to specific CLINs. Actual and forecasted CSP costs can be reported by CLIN. version: 0.4.0 title: ATAT CSP API contact: email: atat-dev+provisioning_api@ccpo.mil tags: - name: access description: >- Operations to manage access to provisioned Portfolios - name: cost description: >- Operations to query for actual and forecasted costs - name: provisioning description: >- Operations to manage provisioned Portfolios paths: '/portfolios': post: tags: - provisioning summary: Adds a new Portfolio security: - oidc: [atat/write-portfolio] description: >- Adds a new Portfolio to be provisioned, including Task Orders and Operators. Once provisioned, Operators can log in to the CSP and begin using provisioned resources and services, funded by the provided Task Order(s). Note that invitations should be sent to all Operator email addresses included in the request. See [#/info/description](#/info/description) and [#/components/schemas](#/components/schemas) for details of these constructs. operationId: addPortfolio parameters: - name: X-Target-Impact-Level description: >- Target Impact Level for this request. Optional header which allows an ATAT implementation to route a request to a more specific environment if more than one is available at a given endpoint. in: header schema: $ref: '#/components/schemas/ImpactLevel' - name: X-Provision-Deadline description: >- Deadline by which the ATAT client expects the Portfolio provisioning process to be complete. Actual values will not be dictated by this specification. in: header schema: type: string format: date-time - name: X-Atat-Api-Version description: >- This header may be provided by an ATAT client implementation to provide context for the ATAT API specification that it expects to be compatible with. Implementations may choose to adapt their response to conform to the expected API version. If not provided by the client, the server should assume the client supports the latest version of this specification. in: header schema: type: string requestBody: description: A new Portfolio required: true content: application/json: schema: $ref: '#/components/schemas/Portfolio' responses: '200': description: Portfolio fully provisioned content: application/json: schema: $ref: '#/components/schemas/Portfolio' '202': description: Provisioning request has been accepted content: application/json: schema: $ref: '#/components/schemas/ProvisioningStatus' headers: Location: description: >- Endpoint which ATAT should poll to receive status updates for this provisioning job. This must be the getProvisioningStatus endpoint for this creation request. schema: type: string example: "https://csp.com/atat/provisioning/123456789/status" required: true '400': description: Invalid input '/portfolios/{portfolioId}': get: tags: - provisioning summary: Gets an existing Portfolio security: - oidc: [atat/read-portfolio] description: Returns a single existing Portfolio, including Task Orders and Operators operationId: getPortfolioById parameters: - name: portfolioId in: path description: ID of the Portfolio required: true schema: type: string - name: X-Target-Impact-Level description: >- Target Impact Level for this request. Optional header which allows an ATAT implementation to route a request to a more specific environment if more than one is available at a given endpoint. in: header schema: $ref: '#/components/schemas/ImpactLevel' - name: X-Atat-Api-Version description: >- This header may be provided by an ATAT client implementation to provide context for the ATAT API specification that it expects to be compatible with. Implementations may choose to adapt their response to conform to the expected API version. If not provided by the client, the server should assume the client supports the latest version of this specification. in: header schema: type: string responses: '200': description: Portfolio successfully retrieved content: application/json: schema: $ref: '#/components/schemas/Portfolio' '400': description: Invalid ID supplied '404': description: Portfolio not found patch: tags: - access security: - oidc: [atat/write-portfolio] description: >- Updates an existing Portfolio. Currently limited to the `administrators` attribute which will add administrators to an existing Portfolio. Note that this is a strictly additive operation; invitations should be sent to all email addresses included in a request. It is expected that removal of access will occur through native CSP mechanisms rather than via ATAT. When an Operator included in this operation does not already have access to the Portfolio in the target Cloud Environment and an invitation should be sent to that Operator's email address. ATAT clients should not specify the `needs_reset` flag for Operators that do not already have access; however, ATAT implementations must ignore the flag for such Operators who do not already have access. When an Operator included in this operator already has access to the Portfolio in the target Cloud Environment and the `needs_reset` attribute is set to `true`, their access should be reset (whether via a token, password, or other vendor-specific means). When an Operator already has access to the Portfolio in the target Cloud Environment and the `needs_reset` attribute is unspecified or `false`, ATAT implementations must not make changes to the user's access nor perform any resets. operationId: patchPortfolio parameters: - name: portfolioId in: path description: ID of the Portfolio required: true schema: type: string - name: X-Target-Impact-Level description: >- Target Impact Level for this request. Optional header which allows an ATAT implementation to route a request to a more specific environment if more than one is available at a given endpoint. in: header schema: $ref: '#/components/schemas/ImpactLevel' - name: X-Atat-Api-Version description: >- This header may be provided by an ATAT client implementation to provide context for the ATAT API specification that it expects to be compatible with. Implementations may choose to adapt their response to conform to the expected API version. If not provided by the client, the server should assume the client supports the latest version of this specification. in: header schema: type: string requestBody: description: A PortfolioPatch object required: true content: application/json: schema: $ref: '#/components/schemas/PortfolioPatch' responses: '200': description: Portfolio successfully updated content: application/json: schema: $ref: '#/components/schemas/PortfolioPatch' '202': description: Provisioning request has been accepted content: application/json: schema: $ref: '#/components/schemas/ProvisioningStatus' headers: Location: description: >- Endpoint which ATAT should poll to receive status updates for this provisioning job. Data at this endpoint must be a valid ProvisioningStatus response. schema: type: string example: "https://csp.com/atat/provisioning/123456789/status" '400': description: Invalid ID supplied '404': description: Portfolio not found '/portfolios/{portfolioId}/cost': get: tags: - cost summary: Returns cost data for a Portfolio, broken down by Task Order & CLINs security: - oidc: [atat/read-cost] description: Queries CSP for actual or forecasted cost data across a Portfolio operationId: getCostsByPortfolio parameters: - name: portfolioId in: path description: ID of the Portfolio required: true schema: type: string - name: start_date in: query description: Start date of the cost data request required: true schema: type: string format: date example: "2021-12-31" - name: end_date in: query description: End date of the cost data request required: true schema: type: string format: date example: "2026-12-31" - name: X-Target-Impact-Level description: >- Target Impact Level for this request. Optional header which allows an ATAT implementation to route a request to a more specific environment if more than one is available at a given endpoint. in: header schema: $ref: '#/components/schemas/ImpactLevel' - name: X-Atat-Api-Version description: >- This header may be provided by an ATAT client implementation to provide context for the ATAT API specification that it expects to be compatible with. Implementations may choose to adapt their response to conform to the expected API version. If not provided by the client, the server should assume the client supports the latest version of this specification. in: header schema: type: string responses: '200': description: Cost operation successful content: application/json: schema: $ref: '#/components/schemas/CostResponseByPortfolio' examples: CostResponseActual: $ref: '#/components/examples/CostResponseByPortfolio' '400': description: Invalid ID or query parameters '404': description: Portfolio not found '/portfolios/{portfolioId}/task-orders': post: tags: - provisioning summary: Adds a new Task Order (TO) security: - oidc: [atat/write-portfolio] description: Adds a new Task Order to an existing Portfolio operationId: addTaskOrder parameters: - name: portfolioId in: path description: ID of the Portfolio required: true schema: type: string - name: X-Target-Impact-Level description: >- Target Impact Level for this request. Optional header which allows an ATAT implementation to route a request to a more specific environment if more than one is available at a given endpoint. in: header schema: $ref: '#/components/schemas/ImpactLevel' - name: X-Atat-Api-Version description: >- This header may be provided by an ATAT client implementation to provide context for the ATAT API specification that it expects to be compatible with. Implementations may choose to adapt their response to conform to the expected API version. If not provided by the client, the server should assume the client supports the latest version of this specification. in: header schema: type: string responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/TaskOrder' '202': description: Provisioning request has been accepted content: application/json: schema: $ref: '#/components/schemas/ProvisioningStatus' headers: Location: description: >- Endpoint which ATAT should poll to receive status updates for this provisioning job. Data at this endpoint must be a valid ProvisioningStatus response. schema: type: string example: "https://csp.com/atat/provisioning/123456789/status" '400': description: Invalid ID supplied '404': description: Portfolio not found requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TaskOrder' '/portfolios/{portfolioId}/task-orders/{taskOrderId}': put: tags: - provisioning summary: Updates an existing Task Order (TO) security: - oidc: [atat/write-portfolio] description: Updates an existing Task Order (TO) operationId: updateTaskOrder parameters: - name: portfolioId in: path description: ID of the Portfolio required: true schema: type: string - name: taskOrderId in: path description: ID of the Task Order required: true schema: type: string - name: X-Target-Impact-Level description: >- Target Impact Level for this request. Optional header which allows an ATAT implementation to route a request to a more specific environment if more than one is available at a given endpoint. in: header schema: $ref: '#/components/schemas/ImpactLevel' - name: X-Atat-Api-Version description: >- This header may be provided by an ATAT client implementation to provide context for the ATAT API specification that it expects to be compatible with. Implementations may choose to adapt their response to conform to the expected API version. If not provided by the client, the server should assume the client supports the latest version of this specification. in: header schema: type: string responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/TaskOrder' '400': description: Invalid ID supplied '404': description: Portfolio or Task Order not found requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TaskOrder' '/portfolios/{portfolioId}/task-orders/{taskOrderId}/clins/{clin}/cost': get: tags: - cost summary: Returns cost data by CLIN security: - oidc: [atat/read-cost] description: Queries CSP for actual or forecasted cost data by CLIN operationId: getCostsByClin parameters: - name: portfolioId in: path description: ID of the Portfolio required: true schema: type: string - name: taskOrderId in: path description: ID of the Task Order required: true schema: type: string - name: clin in: path description: contract line item number required: true schema: type: string - name: start_date in: query description: Start date of the cost data request required: true schema: type: string format: date example: "2021-12-31" - name: end_date in: query description: End date of the cost data request required: true schema: type: string format: date example: "2026-12-31" - name: X-Target-Impact-Level description: >- Target Impact Level for this request. Optional header which allows an ATAT implementation to route a request to a more specific environment if more than one is available at a given endpoint. in: header schema: $ref: '#/components/schemas/ImpactLevel' - name: X-Atat-Api-Version description: >- This header may be provided by an ATAT client implementation to provide context for the ATAT API specification that it expects to be compatible with. Implementations may choose to adapt their response to conform to the expected API version. If not provided by the client, the server should assume the client supports the latest version of this specification. in: header schema: type: string responses: '200': description: Cost operation successful content: application/json: schema: $ref: '#/components/schemas/CostResponseByClin' examples: CostResponseActual: $ref: '#/components/examples/CostResponseByClin' '400': description: Invalid ID or query parameters '404': description: Portfolio not found '/provisioning/{provisioningJobId}/status': get: tags: - provisioning summary: Get the status of a previously issued provisioning job security: - oidc: [atat/read-portfolio] description: >- Queries the CSP for the status of a previously issued provisioning job for which that CSP issued an HTTP 202 response, indicating that the provisioning job was accepted but a response was not available immediately. This allows continuously checking the status to inform the end user. The provisioning job ID must be unique across all provisioning jobs and must never be reused; however, a provisioning job ID must be queryable for at least 168 but no more than 240 hours. operationId: getProvisioningStatus parameters: - name: provisioningJobId in: path description: The ID of the provisioning job required: true schema: type: string - name: X-Target-Impact-Level description: >- Target Impact Level for this request. Optional header which allows an ATAT implementation to route a request to a more specific environment if more than one is available at a given endpoint. in: header schema: $ref: '#/components/schemas/ImpactLevel' responses: '200': description: Get provisioning status successful content: application/json: schema: $ref: '#/components/schemas/ProvisioningStatus' '404': description: Provisioning Job ID not found components: schemas: ProvisioningStatus: type: object description: >- Represents the status of a provisioning job submitted via POST /portfolios required: - provisioning_job_id - status properties: provisioning_job_id: type: string description: >- The ID of the Provisioning job; used for retrieving status to inform end user. This idea must be unique across all provisioning jobs across portfolios. example: "123456789" portfolio_id: type: string description: The ID of the Portfolio for which status is being returned status: type: string enum: - "NOT_STARTED" - "IN_PROGRESS" - "COMPLETE" - "FAILED" PortfolioPatch: properties: administrators: type: array items: $ref: '#/components/schemas/Operator' Portfolio: allOf: - $ref: '#/components/schemas/PortfolioPatch' description: >- Logical container for a set of cloud resources which are paid for by a Task Order & its CLINs. required: - id - name - task_orders - administrators - dashboard_link properties: name: type: string example: "Sample Portfolio name" task_orders: type: array items: allOf: - $ref: '#/components/schemas/TaskOrder' id: description: >- Represents the unqiue ID of the Portfolio created by the vendor. In order to enable the ATAT UI to construct links back to the provisioned environment, this should be the same ID generated internally for the vendor's Portfolio-equivalent construct. type: string readOnly: true example: "csp-portfolio-id-123" dashboard_link: description: >- Represents a deep link to the Portfolio as represented in the vendor's dashboard. Allows ATAT to provide direct links to a Mission Owner's Portfolio within the vendor's environment. type: string format: uri example: "https://vendor.com/account/csp-portfolio-id-123" TaskOrder: type: object description: >- A Task Order and CLINs used to pay for provisioned resources and services required: - id - task_order_number - clins - pop_start_date - pop_end_date properties: id: description: Represents the unique ID of a Task Order. Must be defined by CSPs upon object creation. type: string readOnly: true example: "csp-portfolio-id-123" task_order_number: type: string example: "1234567891234" clins: type: array items: $ref: '#/components/schemas/Clin' pop_start_date: description: Start of period of performance (for this Task Order) type: string format: date example: "2021-07-01" pop_end_date: description: End of period of performance (for this Task Order) type: string format: date example: "2026-07-01" Clin: description: Represents a CLIN in a Task Order additionalProperties: false required: - clin_number - pop_start_date - pop_end_date properties: clin_number: description: Contract Line Item Number (CLIN), 0001 through 9999 type: string pattern: '(?!^0{4}$)^\d{4}$' pop_start_date: description: Start of period of performance (for this CLIN) type: string format: date example: "2021-07-01" pop_end_date: description: End of period of performance (for this CLIN) type: string format: date example: "2022-07-01" Operator: description: >- Represents an individual who should have access to a Portfolio in a target Cloud Environment. required: - email - dod_id - needs_reset properties: email: type: string format: email example: "portfolio.admin@mail.mil" dod_id: type: string minLength: 10 maxLength: 10 needs_reset: description: >- Flag which denotes whether the given Operator's access should be updated (password/token reset or other vendor-specific process) type: boolean default: false ImpactLevel: description: List of available Impact Levels for target Cloud Environments type: string enum: - IL2 - IL4 - IL5 - IL6 - TS CostResponseByClin: description: >- Provides cost data in a format in accordance with the provided CostRequest. For any time periods for which cost data has been generated, actual amounts should be provided. Otherwise, forecast data should be used instead. required: - actual - forecast properties: actual: $ref: '#/components/schemas/CostData' forecast: $ref: '#/components/schemas/CostData' CostResponseByPortfolio: description: >- Provides cost data in a format in accordance with the provided CostRequest. For any time periods for which cost data has been generated, actual amounts should be provided. Otherwise, forecast data should be used instead. Broken down by each CLIN within each Task Order within the given Portfolio. required: - task_orders properties: task_orders: type: array items: properties: task_order_number: type: string clins: type: array items: properties: clin_number: type: string actual: $ref: '#/components/schemas/CostData' forecast: $ref: '#/components/schemas/CostData' CostData: required: - total - results properties: total: type: string description: Total cost (ACTUAL or FORECAST) for all included months in USD example: "12345.67" results: type: array items: properties: month: type: string example: "2022-12" value: type: string description: Cost (ACTUAL or FORECAST) for the given months in USD examples: CostResponseByClin: value: actual: total: "50.00" results: - month: "2021-10" value: "20.00" - month: "2021-11" value: "30.00" CostResponseByPortfolio: value: task_orders: - task_order_number: "1234567891234" clins: - clin_number: "0001" actual: total: "50.00" results: - month: "2021-12" value: "20.00" - month: "2022-01" value: "30.00" forecast: total: "100.00" results: - month: "2022-02" value: "100.00" - clin_number: "0002" actual: total: "750.00" results: - month: "2021-12" value: "50.00" - month: "2022-01" value: "700.00" forecast: total: "1000.00" results: - month: "2022-02" value: "100.00" - month: "2022-03" value: "900.00" securitySchemes: oidc: description: >- Represents an OIDC configuration for an Identity Provider which will be managed by the ATAT client. ATAT implementations should be configured to accept and validate tokens issued by it. Tokens will not contain information or assertions about end-user identity and should purely be used as a means for authentication of the ATAT client implementation and for authorization of that client's actions. ATAT servers must not assume that any user identities specified in request bodies (such as Mission Owners or administrators) can be authenticated using this identity provider and must only use this Identity Provider for the ATAT CSP API. ATAT implementations must leverage the OIDC discovery protocol using the provided URL and must handle key rotation automatically. ## Validation Tokens may include an Audience and if present, ATAT servers must reject any token with an incorrect Audience; however, ATAT servers must accept tokens without an Audience if otherwise valid. ATAT implementations must not limit access to specific subjects and must accept a request from a client presenting valid, unexpired, properly-scoped token. ATAT servers must ignore unrecognized attributes. ## Discovery Configuration The openIdConnectUrl below is meant for integration testing purposes only. It is expected to remain stable but may change occasionally. When this occurs, the ATAT Team will coordinate with the community and update this document as quickly as possible. type: openIdConnect openIdConnectUrl: https://cognito-idp-fips.us-gov-west-1.amazonaws.com/us-gov-west-1_2e6R3aYgi/.well-known/openid-configuration security: - oidc: - atat/read-cost - atat/read-portfolio - atat/write-portfolio