diff --git a/setup.cfg b/setup.cfg index 27dca1e..73c7adb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,6 +28,7 @@ include_package_data = True install_requires = compliance-trestle>=3.3.0 saxonche>=12.4.1.0 + python-docx>=1.1.0 [options.packages.find] include = trestle_fedramp* diff --git a/tests/conftest.py b/tests/conftest.py index 60e5304..e4554d3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,16 +15,27 @@ # limitations under the License. """Common fixtures.""" +import argparse import os import pathlib import sys -from typing import Iterator +from typing import Iterator, Tuple + +from docx import Document # type: ignore +from docx.document import Document as DocxDocument # type: ignore import pytest from pytest import MonkeyPatch +from tests import test_utils + from trestle.cli import Trestle from trestle.common.err import TrestleError +from trestle.core.commands.import_ import ImportCmd + +from trestle_fedramp import const +from trestle_fedramp.core.baselines import BaselineLevel +from trestle_fedramp.core.ssp_reader import FedrampControlDict, FedrampSSPData @pytest.fixture(scope='function') @@ -46,3 +57,100 @@ def tmp_trestle_dir(tmp_path: pathlib.Path, monkeypatch: MonkeyPatch) -> Iterato yield tmp_path finally: os.chdir(pytest_cwd) + + +@pytest.fixture(scope='function') +def tmp_trestle_dir_with_ssp(tmp_path: pathlib.Path, monkeypatch: MonkeyPatch) -> Iterator[Tuple[pathlib.Path, str]]: + """Create initialized trestle workspace and import the model into it.""" + pytest_cwd = pathlib.Path.cwd() + model_name = 'ssp' + file_path = test_utils.JSON_TEST_DATA_PATH / test_utils.TEST_SSP_JSON + os.chdir(tmp_path) + testargs = ['trestle', 'init'] + monkeypatch.setattr(sys, 'argv', testargs) + try: + Trestle().run() + i = ImportCmd() + args = argparse.Namespace( + trestle_root=tmp_path, file=str(file_path), output=model_name, verbose=1, regenerate=False + ) + assert i._run(args) == 0 + except Exception as e: + raise TrestleError(f'Error creating trestle workspace with ssp: {e}') + else: + yield (tmp_path, model_name) + finally: + os.chdir(pytest_cwd) + + +@pytest.fixture(scope='function') +def docx_document() -> Iterator[DocxDocument]: + """Return a docx document.""" + template = pathlib.Path(BaselineLevel.get_template('high')).resolve() + with open(template, 'rb') as file: + document: DocxDocument = Document(file) + yield document + + +@pytest.fixture(scope='function') +def test_ssp_control_dict() -> Iterator[FedrampControlDict]: + """Return a dictionary of control data.""" + control_dict: FedrampControlDict = { + 'AC-1': FedrampSSPData( + control_implementation_description={ + 'a': 'Part a example for AC-1', 'b': 'Part b example for AC-1', 'c': 'Part c example for AC-1' + }, + parameters={ + 'AC-1(a)': 'AC-1(a) parameter example', + 'AC-1(a)(1)': 'AC-1(a)(1) parameter example', + 'AC-1(b)': 'AC-1(b) parameter example', + 'AC-1(c)(1)-1': 'AC-1(c)(1)-1 parameter example', + 'AC-1(c)(1)-2': 'AC-1(c)(1)-2 parameter example', + 'AC-1(c)(2)-1': 'AC-1(c)(2)-1 parameter example', + 'AC-1(c)(2)-2': 'AC-1(c)(2)-2 parameter example', + }, + control_origination=None, + implementation_status=None, + responsible_roles=None + ), + 'AC-2(1)': FedrampSSPData( + control_implementation_description={'': 'Overall description for AC-2(1)'}, + parameters={ + 'AC-2(2)-1': 'AC-2(2)-1 parameter example', + 'AC-2(2)-2': 'AC-2(2)-2 parameter example', + }, + control_origination=[const.FEDRAMP_SP_SYSTEM], + implementation_status=const.FEDRAMP_PLANNED, + responsible_roles=['Customer'] + ), + 'AC-20': FedrampSSPData( + control_implementation_description={ + 'a': 'Part a example for AC-20', + 'b': 'Part b example for AC-20', + }, + parameters={ + 'AC-20(a)': 'AC-20(a) parameter example', + 'AC-20(b)': 'AC-20(b) parameter example', + }, + control_origination=[const.FEDRAMP_SP_CORPORATE, const.FEDRAMP_INHERITED], + implementation_status=const.FEDRAMP_PARTIAL, + responsible_roles=['Admin', 'Customer'] + ), + 'CM-6': FedrampSSPData( + control_implementation_description={ + 'a': 'Part a example for CM-6', + 'b': 'Part b example for CM-6', + 'c': 'Part c example for CM-6', + 'd': 'Part d example for CM-6', + }, + parameters={ + 'CM-6(a)': 'CM-6(a) parameter example', + 'CM-6(c)-1': 'CM-6(c)-1 parameter example', + 'CM-6(c)-2': 'CM-6(c)-2 parameter example', + }, + control_origination=[const.FEDRAMP_SHARED], + implementation_status=const.FEDRAMP_IMPLEMENTED, + responsible_roles=['Provider'] + ) + } + yield control_dict diff --git a/tests/data/json/simplified_fedramp_ssp_template.json b/tests/data/json/simplified_fedramp_ssp_template.json new file mode 100644 index 0000000..78b973d --- /dev/null +++ b/tests/data/json/simplified_fedramp_ssp_template.json @@ -0,0 +1,2959 @@ +{ + "system-security-plan": { + "uuid": "9809eddf-2cd5-468f-97c5-9769905d0629", + "metadata": { + "title": "Test FedRAMP System Security Plan (SSP)", + "published": "2023-08-31T00:00:00Z", + "last-modified": "2023-08-31T00:00:00Z", + "version": "test-oscal-1.0.4", + "oscal-version": "1.0.4", + "revisions": [ + { + "published": "2023-06-30T00:00:00Z", + "version": "1.0", + "oscal-version": "1.0.4", + "props": [ + { + "name": "party-uuid", + "uuid": "528974e9-fcde-494f-a2fa-35d6f1e31171", + "ns": "https://fedramp.gov/ns/oscal", + "value": "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + } + ], + "remarks": "Initial publication." + } + ], + "props": [ + { + "name": "marking", + "value": "Controlled Unclassified Information" + }, + { + "name": "resolution-resource", + "ns": "https://fedramp.gov/ns/oscal", + "value": "ace2963d-ecb4-4be5-bdd0-1f6fd7610f41" + } + ], + "roles": [ + { + "id": "fedramp-pmo", + "title": "FedRAMP Program Management Office", + "description": "The FedRAMP PMO resides within GSA and supports agencies and cloud service providers through the FedRAMP authorization process and maintains a secure repository of FedRAMP authorizations to enable reuse of security packages." + }, + { + "id": "fedramp-jab", + "title": "FedRAMP Program Management Office", + "description": "Members of the JAB include the chief information officers (CIOs) from the Department of Defense, Department of Homeland Security, and General Services Administration. The JAB serves as the primary governance and decision-making body for FedRAMP." + }, + { + "id": "prepared-by", + "title": "Prepared By", + "description": "The organization that prepared this SSP. If developed in-house, this is the CSP itself." + }, + { + "id": "prepared-for", + "title": "Prepared For", + "description": "The organization for which this SSP was prepared. Typically the CSP." + }, + { + "id": "content-approver", + "title": "System Security Plan Approval", + "description": "The individual or individuals accountable for the accuracy of this SSP." + }, + { + "id": "cloud-service-provider", + "title": "Cloud Service Provider", + "short-name": "CSP" + }, + { + "id": "system-owner", + "title": "Information System Owner", + "description": "The individual within the CSP who is ultimately accountable for everything related to this system." + }, + { + "id": "authorizing-official", + "title": "Authorizing Official", + "description": "The individual or individuals who must grant this system an authorization to operate." + }, + { + "id": "authorizing-official-poc", + "title": "Authorizing Official's Point of Contact", + "description": "The individual representing the authorizing official." + }, + { + "id": "system-poc-management", + "title": "Information System Management Point of Contact (POC)", + "description": "The highest level manager who responsible for system operation on behalf of the System Owner." + }, + { + "id": "system-poc-technical", + "title": "Information System Technical Point of Contact", + "description": "The individual or individuals leading the technical operation of the system." + }, + { + "id": "system-poc-other", + "title": "General Point of Contact (POC)", + "description": "A general point of contact for the system, designated by the system owner." + }, + { + "id": "information-system-security-officer", + "title": "System Information System Security Officer (or Equivalent)", + "description": "The individual accountable for the security posture of the system on behalf of the system owner." + }, + { + "id": "privacy-poc", + "title": "Privacy Official's Point of Contact", + "description": "The individual responsible for the privacy threshold analysis and if necessary the privacy impact assessment." + }, + { + "id": "asset-owner", + "title": "Owner of an inventory item within the system." + }, + { + "id": "asset-administrator", + "title": "Administrative responsibility an inventory item within the system." + }, + { + "id": "isa-poc-local", + "title": "ICA POC (Local)", + "description": "The point of contact for an interconnection on behalf of this system.", + "remarks": "Remove this role if there are no ICAs." + }, + { + "id": "isa-poc-remote", + "title": "ICA POC (Remote)", + "description": "The point of contact for an interconnection on behalf of this external system to which this system connects.", + "remarks": "Remove this role if there are no ICAs." + }, + { + "id": "isa-authorizing-official-local", + "title": "ICA Signatory (Local)", + "description": "Responsible for signing an interconnection security agreement on behalf of this system.", + "remarks": "Remove this role if there are no ICAs." + }, + { + "id": "isa-authorizing-official-remote", + "title": "ICA Signatory (Remote)", + "description": "Responsible for signing an interconnection security agreement on behalf of the external system to which this system connects.", + "remarks": "Remove this role if there are no ICAs." + }, + { + "id": "consultant", + "title": "Consultant", + "description": "Any consultants involved with developing or maintaining this content." + }, + { + "id": "customer", + "title": "Customer", + "description": "Represents any customers of this system as may be necessary for assigning customer responsibility." + }, + { + "id": "admin-unix", + "title": "[SAMPLE]Unix Administrator", + "description": "This is a sample role." + }, + { + "id": "admin-client", + "title": "[SAMPLE]Client Administrator", + "description": "This is a sample role." + } + ], + "locations": [ + { + "uuid": "27b78960-59ef-4619-82b0-ae20b9c709ac", + "title": "CSP HQ", + "address": { + "type": "work", + "addr-lines": [ + "Suite 0000", + "1234 Some Street" + ], + "city": "Haven", + "state": "ME", + "postal-code": "00000" + }, + "remarks": "There must be one location identifying the CSP's primary business address, such as the CSP's HQ, or the address of the system owner's primary business location." + } + ], + "parties": [ + { + "uuid": "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb", + "type": "organization", + "name": "Cloud Service Provider (CSP) Name", + "short-name": "CSP Acronym/Short Name", + "links": [ + { + "href": "#31a46c4f-2959-4287-bc1c-67297d7da60b", + "rel": "logo" + } + ], + "location-uuids": [ + "27b78960-59ef-4619-82b0-ae20b9c709ac" + ], + "remarks": "Replace sample CSP information.\n\nCSP information must be present and associated with the \\\"cloud-service-provider\\\" role via `responsible-party`." + }, + { + "uuid": "77e0e2c8-2560-4fe9-ac78-c3ff4ffc9f6d", + "type": "organization", + "name": "Federal Risk and Authorization Management Program: Program Management Office", + "short-name": "FedRAMP PMO", + "links": [ + { + "href": "https://fedramp.gov", + "rel": "homepage" + }, + { + "href": "#a2381e87-3d04-4108-a30b-b4d2f36d001f", + "rel": "logo" + }, + { + "href": "#1a23a771-d481-4594-9a1a-71d584fa4123", + "rel": "reference" + } + ], + "email-addresses": [ + "info@fedramp.gov" + ], + "addresses": [ + { + "type": "work", + "addr-lines": [ + "1800 F St. NW" + ], + "city": "Washington", + "state": "DC", + "postal-code": "20006", + "country": "US" + } + ], + "remarks": "This party entry must be present in a FedRAMP SSP.\n\nThe uuid may be different; however, the uuid must be associated with the \\\"fedramp-pmo\\\" role in the responsible-party assemblies." + }, + { + "uuid": "49017ec3-9f51-4dbd-9253-858c2b1295fd", + "type": "organization", + "name": "Federal Risk and Authorization Management Program: Joint Authorization Board", + "short-name": "FedRAMP JAB", + "links": [ + { + "href": "#a2381e87-3d04-4108-a30b-b4d2f36d001f", + "rel": "logo" + } + ], + "remarks": "This party entry must be present in a FedRAMP SSP.\n\nThe uuid may be different; however, the uuid must be associated with the \\\"fedramp-jab\\\" role in the responsible-party assemblies." + }, + { + "uuid": "78992555-4a99-4eaa-868c-f2c249679dd3", + "type": "organization", + "name": "External Organization", + "short-name": "External", + "remarks": "Generic placeholder for any external organization." + }, + { + "uuid": "f595397b-cbe4-4a87-8c86-9bff91c4e7fd", + "type": "organization", + "name": "Agency Name", + "short-name": "A.N.", + "remarks": "Generic placeholder for an authorizing agency." + }, + { + "uuid": "8e3d39da-4851-4d2a-adb5-4b5585ded952", + "type": "organization", + "name": "Name of Consulting Org", + "short-name": "NOCO", + "links": [ + { + "href": "https://example.com" + }, + { + "href": "#2c1747d6-874a-49a2-8488-2fd9735416bf", + "rel": "logo" + } + ], + "email-addresses": [ + "poc@example.com" + ], + "addresses": [ + { + "type": "work", + "addr-lines": [ + "3333 Corporate Way" + ], + "city": "Washington", + "state": "DC", + "postal-code": "00000", + "country": "US" + } + ] + }, + { + "uuid": "80361ec4-bfce-4b5c-85c8-313d6ebd220b", + "type": "organization", + "name": "[SAMPLE]Remote System Org Name" + }, + { + "uuid": "09ad840f-aa79-43aa-9f22-25182c2ab11b", + "type": "person", + "name": "[SAMPLE]ICA POC's Name", + "props": [ + { + "name": "job-title", + "value": "Individual's Title" + } + ], + "email-addresses": [ + "person@ica.example.org" + ], + "telephone-numbers": [ + { + "number": "2025551212" + } + ], + "member-of-organizations": [ + "80361ec4-bfce-4b5c-85c8-313d6ebd220b" + ] + }, + { + "uuid": "f0bc13a4-3303-47dd-80d3-380e159c8362", + "type": "organization", + "name": "[SAMPLE]Example IaaS Provider", + "short-name": "E.I.P.", + "remarks": "Underlying service provider. Leveraged Authorization." + }, + { + "uuid": "3360e343-9860-4bda-9dfc-ff427c3dfab6", + "type": "person", + "name": "[SAMPLE]Person Name 1", + "props": [ + { + "name": "job-title", + "value": "Individual's Title" + }, + { + "name": "mail-stop", + "value": "Mailstop A-1" + } + ], + "email-addresses": [ + "name@example.com" + ], + "telephone-numbers": [ + { + "number": "2020000001" + } + ], + "location-uuids": [ + "27b78960-59ef-4619-82b0-ae20b9c709ac" + ], + "member-of-organizations": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ] + }, + { + "uuid": "36b8d6c0-3b25-42cc-b529-cf4066145cdd", + "type": "person", + "name": "[SAMPLE]Person Name 2", + "props": [ + { + "name": "job-title", + "value": "Individual's Title" + } + ], + "email-addresses": [ + "name@example.com" + ], + "telephone-numbers": [ + { + "number": "2020000002" + } + ], + "addresses": [ + { + "type": "work", + "addr-lines": [ + "Address Line" + ], + "city": "City", + "state": "ST", + "postal-code": "00000", + "country": "US" + } + ], + "member-of-organizations": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ] + }, + { + "uuid": "0cec09d9-20c6-470b-9ffc-85763375880b", + "type": "person", + "name": "[SAMPLE]Person Name 3", + "props": [ + { + "name": "job-title", + "value": "Individual's Title" + } + ], + "email-addresses": [ + "name@example.com" + ], + "telephone-numbers": [ + { + "number": "2020000003" + } + ], + "addresses": [ + { + "type": "work", + "addr-lines": [ + "Address Line" + ], + "city": "City", + "state": "ST", + "postal-code": "00000", + "country": "US" + } + ], + "member-of-organizations": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ] + }, + { + "uuid": "f75e21f6-43d8-46ab-890d-7f2eebc5a830", + "type": "person", + "name": "[SAMPLE]Person Name 4", + "props": [ + { + "name": "job-title", + "value": "Individual's Title" + } + ], + "email-addresses": [ + "name@example.com" + ], + "telephone-numbers": [ + { + "number": "2020000004" + } + ], + "addresses": [ + { + "type": "work", + "addr-lines": [ + "Address Line" + ], + "city": "City", + "state": "ST", + "postal-code": "00000", + "country": "US" + } + ], + "member-of-organizations": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ] + }, + { + "uuid": "132953a9-640c-46f7-9de9-3fa15ec99361", + "type": "person", + "name": "[SAMPLE]Person Name 5", + "props": [ + { + "name": "job-title", + "value": "Individual's Title" + } + ], + "email-addresses": [ + "name@example.com" + ], + "telephone-numbers": [ + { + "number": "2020000005" + } + ], + "addresses": [ + { + "type": "work", + "addr-lines": [ + "Address Line" + ], + "city": "City", + "state": "ST", + "postal-code": "00000", + "country": "US" + } + ], + "member-of-organizations": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ] + }, + { + "uuid": "4fded5fd-7a65-47ea-bd76-df57c46e27d1", + "type": "person", + "name": "[SAMPLE]Person Name 6", + "props": [ + { + "name": "job-title", + "value": "Individual's Title" + } + ], + "email-addresses": [ + "name@example.com" + ], + "telephone-numbers": [ + { + "number": "2020000006" + } + ], + "addresses": [ + { + "type": "work", + "addr-lines": [ + "Address Line" + ], + "city": "City", + "state": "ST", + "postal-code": "00000", + "country": "US" + } + ], + "member-of-organizations": [ + "78992555-4a99-4eaa-868c-f2c249679dd3" + ] + }, + { + "uuid": "db234cb7-1776-425c-9ac4-b067c1723011", + "type": "person", + "name": "[SAMPLE]Person Name 7", + "props": [ + { + "name": "job-title", + "value": "Individual's Title" + } + ], + "email-addresses": [ + "name@example.com" + ], + "telephone-numbers": [ + { + "number": "2020000007" + } + ], + "addresses": [ + { + "type": "work", + "addr-lines": [ + "Address Line" + ], + "city": "City", + "state": "ST", + "postal-code": "00000", + "country": "US" + } + ], + "member-of-organizations": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ] + }, + { + "uuid": "b306f5af-b93a-4a7f-a2b2-37a44fc92a79", + "type": "organization", + "name": "[SAMPLE] IT Department" + }, + { + "uuid": "59cdc953-5902-4fa4-a878-f3163854624c", + "type": "organization", + "name": "[SAMPLE]Security Team" + } + ], + "responsible-parties": [ + { + "role-id": "cloud-service-provider", + "party-uuids": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ], + "remarks": "Exactly one" + }, + { + "role-id": "prepared-by", + "party-uuids": [ + "3360e343-9860-4bda-9dfc-ff427c3dfab6" + ], + "remarks": "Exactly one" + }, + { + "role-id": "prepared-for", + "party-uuids": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ] + }, + { + "role-id": "content-approver", + "party-uuids": [ + "3360e343-9860-4bda-9dfc-ff427c3dfab6", + "36b8d6c0-3b25-42cc-b529-cf4066145cdd" + ], + "remarks": "One or more" + }, + { + "role-id": "system-owner", + "party-uuids": [ + "3360e343-9860-4bda-9dfc-ff427c3dfab6" + ], + "remarks": "Exactly one" + }, + { + "role-id": "authorizing-official", + "party-uuids": [ + "49017ec3-9f51-4dbd-9253-858c2b1295fd", + "4fded5fd-7a65-47ea-bd76-df57c46e27d1" + ], + "remarks": "One or more" + }, + { + "role-id": "system-poc-management", + "party-uuids": [ + "0cec09d9-20c6-470b-9ffc-85763375880b" + ], + "remarks": "Exactly one" + }, + { + "role-id": "system-poc-technical", + "party-uuids": [ + "f75e21f6-43d8-46ab-890d-7f2eebc5a830" + ], + "remarks": "Exactly one" + }, + { + "role-id": "information-system-security-officer", + "party-uuids": [ + "132953a9-640c-46f7-9de9-3fa15ec99361" + ], + "remarks": "Exactly one" + }, + { + "role-id": "authorizing-official-poc", + "party-uuids": [ + "4fded5fd-7a65-47ea-bd76-df57c46e27d1" + ], + "remarks": "Exactly one" + }, + { + "role-id": "privacy-poc", + "party-uuids": [ + "db234cb7-1776-425c-9ac4-b067c1723011" + ], + "remarks": "Exactly one" + }, + { + "role-id": "fedramp-pmo", + "party-uuids": [ + "77e0e2c8-2560-4fe9-ac78-c3ff4ffc9f6d" + ], + "remarks": "Exactly one" + }, + { + "role-id": "fedramp-jab", + "party-uuids": [ + "49017ec3-9f51-4dbd-9253-858c2b1295fd" + ], + "remarks": "Exactly one" + } + ], + "remarks": "This OSCAL-based FedRAMP SSP Template can be used for the FedRAMP Low, Moderate, and High baselines.\n\nGuidance for OSCAL-based FedRAMP Tailored Low Impact - Software as a Service (LI-SaaS) content has not yet been developed." + }, + "import-profile": { + "href": "https://raw.githubusercontent.com/GSA/fedramp-automation/5f44c1b09af13d203f008be6bd33603ad7cb0202/dist/content/rev5/baselines/json/FedRAMP_rev5_MODERATE-baseline-resolved-profile_catalog.json", + "remarks": "This example points to the FedRAMP Rev 5 Moderate baseline that is part of the official FedRAMP 1.0.4 release.\n\nMust adjust accordingly for applicable baseline and revision." + }, + "system-characteristics": { + "system-ids": [ + { + "identifier-type": "https://fedramp.gov", + "id": "F00000000" + } + ], + "system-name": "System's Full Name", + "system-name-short": "System's Short Name or Acronym", + "description": "[Insert CSO Name] is delivered as [a/an] [insert based on the Service Model above] offering using a multi-tenant [insert based on the Deployment Model above] cloud computing environment. It is available to [Insert scope of customers in accordance with instructions above (for example, the public, federal, state, local, and tribal governments, as well as research institutions, federal contractors, government contractors etc.)].\n\nNOTE: Additional description, including the purpose and functions of this system may be added here. This includes any narrative text usually included in section 9.1 of the SSP.\n\nNOTE: The description is expected to be at least 32 words in length.", + "props": [ + { + "name": "cloud-service-model", + "value": "saas", + "remarks": "Remarks are required if service model is \\\"other\\\". Optional otherwise." + }, + { + "name": "cloud-deployment-model", + "value": "government-only-cloud", + "remarks": "Remarks are required if deployment model is \\\"hybrid-cloud\\\" or \\\"other\\\". Optional otherwise." + }, + { + "name": "identity-assurance-level", + "value": "2" + }, + { + "name": "authenticator-assurance-level", + "value": "2" + }, + { + "name": "federation-assurance-level", + "value": "2" + }, + { + "name": "fully-operational-date", + "ns": "https://fedramp.gov/ns/oscal", + "value": "yyyy-mm-ddThh:mmZ" + }, + { + "name": "authorization-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "fedramp-agency" + } + ], + "security-sensitivity-level": "fips-199-moderate", + "system-information": { + "information-types": [ + { + "uuid": "06ecba4f-db96-4491-a3a2-7febfa227435", + "title": "Information Type Name", + "description": "A description of the information.", + "categorizations": [ + { + "system": "https://doi.org/10.6028/NIST.SP.800-60v2r1", + "information-type-ids": [ + "C.2.4.1" + ] + } + ], + "confidentiality-impact": { + "base": "fips-199-moderate", + "selected": "fips-199-moderate", + "adjustment-justification": "Required if the base and selected values do not match." + }, + "integrity-impact": { + "base": "fips-199-moderate", + "selected": "fips-199-moderate", + "adjustment-justification": "Required if the base and selected values do not match." + }, + "availability-impact": { + "base": "fips-199-moderate", + "selected": "fips-199-moderate", + "adjustment-justification": "Required if the base and selected values do not match." + } + } + ] + }, + "security-impact-level": { + "security-objective-confidentiality": "fips-199-moderate", + "security-objective-integrity": "fips-199-moderate", + "security-objective-availability": "fips-199-moderate" + }, + "status": { + "state": "operational", + "remarks": "Remarks are optional if status/state is \\\"operational\\\".\n\nRemarks are required otherwise." + }, + "authorization-boundary": { + "description": "A holistic, top-level explanation of the FedRAMP authorization boundary.", + "diagrams": [ + { + "uuid": "dbf46c27-52a9-49c4-beb6-b6399cd75497", + "description": "A diagram-specific explanation.", + "links": [ + { + "href": "#d2eb3c18-6754-4e3a-a933-03d289e3fad5", + "rel": "diagram" + } + ], + "caption": "Authorization Boundary Diagram" + } + ] + }, + "network-architecture": { + "description": "A holistic, top-level explanation of the network architecture.", + "diagrams": [ + { + "uuid": "e97c3395-433a-48c1-8cc7-dd1e1555941c", + "description": "A diagram-specific explanation.", + "links": [ + { + "href": "#61081e81-850b-43c1-bf43-1ecbddcb9e7f", + "rel": "diagram" + } + ], + "caption": "Network Diagram" + } + ] + }, + "data-flow": { + "description": "A holistic, top-level explanation of the system's data flows.", + "diagrams": [ + { + "uuid": "e3b98448-4219-46a5-b229-412423c566f3", + "description": "A diagram-specific explanation.", + "links": [ + { + "href": "#ac5d7535-f3b8-45d3-bf3b-735c82c64547", + "rel": "diagram" + } + ], + "caption": "Data Flow Diagram" + } + ] + } + }, + "system-implementation": { + "props": [ + { + "name": "users-internal", + "ns": "https://fedramp.gov/ns/oscal", + "value": "0" + }, + { + "name": "users-external", + "ns": "https://fedramp.gov/ns/oscal", + "value": "0" + }, + { + "name": "users-internal-future", + "ns": "https://fedramp.gov/ns/oscal", + "value": "0" + }, + { + "name": "users-external-future", + "ns": "https://fedramp.gov/ns/oscal", + "value": "0" + } + ], + "leveraged-authorizations": [ + { + "uuid": "5a9c98ab-8e5e-433d-a7bd-515c07cd1497", + "title": "GovCloud", + "props": [ + { + "name": "leveraged-system-identifier", + "ns": "https://fedramp.gov/ns/oscal", + "value": "F1603047866" + }, + { + "name": "authorization-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "fedramp-agency" + }, + { + "name": "impact-level", + "ns": "https://fedramp.gov/ns/oscal", + "value": "moderate" + } + ], + "links": [ + { + "href": "//path/to/leveraged_system_ssp.json" + }, + { + "href": "//path/to/leveraged_system_legacy_crm.xslt" + }, + { + "href": "//path/to/leveraged_system_responsibility_and_inheritance.json" + } + ], + "party-uuid": "f0bc13a4-3303-47dd-80d3-380e159c8362", + "date-authorized": "2015-01-01", + "remarks": "Use one leveraged-authorization assembly for each underlying system. In the legacy world, these may be general support systems.\n\nThe link fields are optional, but preferred when known. Often, a leveraging system's SSP author will not have access to the leveraged system's SSP, but should have access to the leveraged system's CRM." + } + ], + "users": [ + { + "uuid": "9cb0fab0-78bd-44ba-bcb8-3e9801cc952f", + "title": "[SAMPLE]Unix System Administrator", + "props": [ + { + "name": "sensitivity", + "ns": "https://fedramp.gov/ns/oscal", + "value": "high-risk" + }, + { + "name": "privilege-level", + "value": "privileged" + }, + { + "name": "authentication-method", + "ns": "https://fedramp.gov/ns/oscal", + "value": "multi-factor OTP device" + }, + { + "name": "type", + "value": "internal" + } + ], + "role-ids": [ + "admin-unix" + ], + "authorized-privileges": [ + { + "title": "Full administrative access (root)", + "functions-performed": [ + "Add/remove users and hardware", + "install and configure software", + "OS updates, patches and hotfixes", + "perform backups" + ] + } + ] + }, + { + "uuid": "16ec71e7-025c-43e4-9d3f-3acb485fac2e", + "title": "[SAMPLE]Client Administrator", + "props": [ + { + "name": "sensitivity", + "ns": "https://fedramp.gov/ns/oscal", + "value": "moderate" + }, + { + "name": "privilege-level", + "value": "non-privileged" + }, + { + "name": "authentication-method", + "ns": "https://fedramp.gov/ns/oscal", + "value": "memorized seccret plus SF OTP device" + }, + { + "name": "type", + "value": "external" + } + ], + "role-ids": [ + "admin-client" + ], + "authorized-privileges": [ + { + "title": "Portal administration", + "functions-performed": [ + "Add/remove client users", + "Create, modify and delete client applications" + ] + } + ] + }, + { + "uuid": "ba7708c1-4041-48ab-9b7b-1ddb5e175fe0", + "title": "[SAMPLE]Program Director", + "props": [ + { + "name": "sensitivity", + "ns": "https://fedramp.gov/ns/oscal", + "value": "limited" + }, + { + "name": "privilege-level", + "value": "no-logical-access" + }, + { + "name": "authentication-method", + "ns": "https://fedramp.gov/ns/oscal", + "value": "not-applicable" + }, + { + "name": "type", + "value": "internal" + } + ], + "role-ids": [ + "information-system-security-officer", + "isa-poc-local", + "isa-authorizing-official-local" + ], + "authorized-privileges": [ + { + "title": "Administrative Access Approver", + "functions-performed": [ + "Approves access requests for administrative accounts." + ] + }, + { + "title": "Access Approver", + "functions-performed": [ + "Approves access requests for administrative accounts." + ] + } + ] + }, + { + "uuid": "73ae456f-5581-4ff7-9ada-49fc057b2e0b", + "title": "[SAMPLE]ISA POC", + "props": [ + { + "name": "sensitivity", + "ns": "https://fedramp.gov/ns/oscal", + "value": "not-applicable" + }, + { + "name": "privilege-level", + "value": "no-logical-access" + }, + { + "name": "authentication-method", + "ns": "https://fedramp.gov/ns/oscal", + "value": "not-applicable" + }, + { + "name": "type", + "value": "external" + } + ], + "role-ids": [ + "isa-poc-remote", + "isa-authorizing-official-remote" + ], + "authorized-privileges": [ + { + "title": "External System Access Provider", + "functions-performed": [ + "Authorizes access to external interconnected system." + ] + } + ] + } + ], + "components": [ + { + "uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "type": "this-system", + "title": "This System", + "description": "The entire system as depicted in the system authorization boundary\n\nEmail is employed", + "status": { + "state": "operational" + } + }, + { + "uuid": "95beec7e-6f82-4aaa-8211-969cd7c1f1ab", + "type": "validation", + "title": "[SAMPLE]Cryptographic Module Name", + "description": "Provide a description and any pertinent note regarding the use of this CM.\n\nFor data-at-rest modules, describe type of encryption implemented (e.g., full disk, file, record-level, etc.)\n\nLastly, provide any supporting notes on FIPS status (e.g. historical) or lack of FIPS compliance (e.g., Module in Process).", + "props": [ + { + "name": "asset-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "cryptographic-module" + }, + { + "name": "vendor-name", + "ns": "https://fedramp.gov/ns/oscal", + "value": "CM Vendor" + }, + { + "name": "cryptographic-module-usage", + "ns": "https://fedramp.gov/ns/oscal", + "value": "data-at-rest" + }, + { + "name": "validation-type", + "value": "fips-140-2" + }, + { + "name": "validation-reference", + "value": "3928" + } + ], + "links": [ + { + "href": "https://csrc.nist.gov/projects/cryptographic-module-validation-program/Certificate/3928", + "rel": "validation-details" + } + ], + "status": { + "state": "operational" + } + }, + { + "uuid": "1eaaabbd-b3a6-4316-a868-7b815e7c40f5", + "type": "validation", + "title": "[SAMPLE]Cryptographic Module Name", + "description": "Provide a description and any pertinent note regarding the use of this CM.\n\nFor example, any supporting notes on FIPS status (e.g. historical) or lack of FIPS compliance (e.g., Module in Process).", + "props": [ + { + "name": "asset-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "cryptographic-module" + }, + { + "name": "vendor-name", + "ns": "https://fedramp.gov/ns/oscal", + "value": "CM Vendor" + }, + { + "name": "cryptographic-module-usage", + "ns": "https://fedramp.gov/ns/oscal", + "value": "data-in-transit" + }, + { + "name": "validation-type", + "value": "fips-140-3" + }, + { + "name": "validation-reference", + "value": "3920" + } + ], + "links": [ + { + "href": "https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3920", + "rel": "validation-details" + } + ], + "status": { + "state": "operational" + } + }, + { + "uuid": "e82e6e07-0c62-417e-8a19-3744991b4c65", + "type": "leveraged-system", + "title": "Name of Leveraged System", + "description": "If the leveraged system owner provides a UUID for their system (such as in an OSCAL-based CRM), it should be reflected in the `inherited-uuid` property.\n\nMust include all leveraged services and features from the leveraged authorization here.", + "props": [ + { + "name": "asset-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "paas" + }, + { + "name": "isa-title", + "value": "system interconnection agreement" + }, + { + "name": "isa-date", + "value": "2023-01-01T00:00:00Z" + }, + { + "name": "nature-of-agreement", + "ns": "https://fedramp.gov/ns/oscal", + "value": "SLA" + }, + { + "name": "ipv4-address", + "value": "172.0.0.0" + }, + { + "name": "ipv6-address", + "value": "::" + }, + { + "name": "direction", + "value": "incoming" + }, + { + "name": "information", + "ns": "https://fedramp.gov/ns/oscal", + "value": "describe information being transferred" + }, + { + "name": "interconnection-data-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "C.3.5.1", + "class": "fedramp" + }, + { + "name": "interconnection-data-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "C.3.5.8", + "class": "fedramp" + }, + { + "name": "leveraged-authorization-uuid", + "value": "5a9c98ab-8e5e-433d-a7bd-515c07cd1497" + }, + { + "name": "implementation-point", + "value": "external" + }, + { + "name": "inherited-uuid", + "value": "11111111-0000-4000-9001-000000000001" + } + ], + "status": { + "state": "operational" + } + }, + { + "uuid": "77A1614A-57B3-4B32-9FEE-613A6520EC58", + "type": "service", + "title": "Service Provided by Leveraged System", + "description": "If the leveraged system owner provides a UUID for their service (such as in an OSCAL-based CRM), it should be reflected in the `inherited-uuid` property.\n\nMust include all leveraged services and features from the leveraged authorization here.", + "props": [ + { + "name": "leveraged-authorization-uuid", + "value": "5a9c98ab-8e5e-433d-a7bd-515c07cd1497" + }, + { + "name": "implementation-point", + "value": "external" + }, + { + "name": "inherited-uuid", + "value": "11111111-0000-4000-9001-000000000002" + } + ], + "links": [ + { + "href": "60f92bcf-f353-4236-9803-2a5d417555f4", + "rel": "used-by" + } + ], + "status": { + "state": "operational" + } + }, + { + "uuid": "2812ef51-61e7-4505-afbb-da5a073a2a5c", + "type": "interconnection", + "title": "[EXAMPLE]Authorized Connection Information System Name", + "description": "Describe the purpose of the external system/service; specifically, provide reasons for connectivity (e.g., system monitoring, system alerting, download updates, etc.).", + "props": [ + { + "name": "service-processor", + "ns": "https://fedramp.gov/ns/oscal", + "value": "[SAMPLE] Telco Name" + }, + { + "name": "interconnection-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "1" + }, + { + "name": "nature-of-agreement", + "ns": "https://fedramp.gov/ns/oscal", + "value": "Contract" + }, + { + "name": "still-supported", + "ns": "https://fedramp.gov/ns/oscal", + "value": "yes" + }, + { + "name": "interconnection-data-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "C.3.5.1", + "class": "fedramp" + }, + { + "name": "interconnection-data-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "C.3.5.8", + "class": "fedramp" + }, + { + "name": "interconnection-data-categorization", + "ns": "https://fedramp.gov/ns/oscal", + "value": "low", + "class": "C.3.5.1" + }, + { + "name": "interconnection-data-categorization", + "ns": "https://fedramp.gov/ns/oscal", + "value": "moderate", + "class": "C.3.5.8" + }, + { + "name": "authorized-users", + "ns": "https://fedramp.gov/ns/oscal", + "value": "SecOps engineers" + }, + { + "name": "interconnection-compliance", + "ns": "https://fedramp.gov/ns/oscal", + "value": "PCI SOC 2", + "class": "fedramp" + }, + { + "name": "interconnection-compliance", + "ns": "https://fedramp.gov/ns/oscal", + "value": "ISO/IEC 27001", + "class": "fedramp" + }, + { + "name": "interconnection-hosting-environment", + "ns": "https://fedramp.gov/ns/oscal", + "value": "PaaS" + }, + { + "name": "interconnection-risk", + "ns": "https://fedramp.gov/ns/oscal", + "value": "None" + }, + { + "name": "isa-title", + "value": "system interconnection agreement" + }, + { + "name": "isa-date", + "value": "2023-01-01T00:00:00Z" + }, + { + "name": "ipv4-address", + "value": "10.1.1.1", + "class": "local" + }, + { + "name": "ipv4-address", + "value": "10.2.2.2", + "class": "remote" + }, + { + "name": "ipv6-address", + "value": "::ffff:10.2.2.2" + }, + { + "name": "direction", + "value": "incoming" + }, + { + "name": "direction", + "value": "outgoing" + }, + { + "name": "information", + "ns": "https://fedramp.gov/ns/oscal", + "value": "Describe the information being transmitted." + }, + { + "name": "port", + "ns": "https://fedramp.gov/ns/oscal", + "value": "80", + "class": "remote" + }, + { + "name": "interconnection-security", + "ns": "https://fedramp.gov/ns/oscal", + "value": "ipsec", + "remarks": "If \\\"other\\\", remarks are required. Optional otherwise." + } + ], + "links": [ + { + "href": "#9d6cf2b4-8e88-4040-a33c-7bc206553a1a", + "rel": "isa-agreement" + } + ], + "status": { + "state": "operational" + }, + "responsible-roles": [ + { + "role-id": "isa-poc-remote", + "party-uuids": [ + "09ad840f-aa79-43aa-9f22-25182c2ab11b" + ] + }, + { + "role-id": "isa-poc-local", + "party-uuids": [ + "09ad840f-aa79-43aa-9f22-25182c2ab11b" + ] + }, + { + "role-id": "isa-authorizing-official-remote", + "party-uuids": [ + "09ad840f-aa79-43aa-9f22-25182c2ab11b" + ] + }, + { + "role-id": "isa-authorizing-official-local", + "party-uuids": [ + "09ad840f-aa79-43aa-9f22-25182c2ab11b" + ] + } + ], + "remarks": "Optional notes about this interconnection" + }, + { + "uuid": "05ceb8df-52e7-49db-9719-891723f366bd", + "type": "software", + "title": "[SAMPLE]Product Name", + "description": "FUNCTION: Describe typical component function.", + "props": [ + { + "name": "asset-type", + "value": "operating-system" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + }, + { + "name": "vendor-name", + "value": "Vendor Name" + }, + { + "name": "model", + "value": "Model Number" + }, + { + "name": "version", + "value": "Version Number" + }, + { + "name": "patch-level", + "value": "Patch Level" + } + ], + "links": [ + { + "href": "#95beec7e-6f82-4aaa-8211-969cd7c1f1ab", + "rel": "validation" + } + ], + "status": { + "state": "operational" + }, + "responsible-roles": [ + { + "role-id": "admin-unix", + "party-uuids": [ + "3360e343-9860-4bda-9dfc-ff427c3dfab6" + ] + } + ], + "remarks": "COMMENTS: Provide other comments as needed." + }, + { + "uuid": "1541015b-6d19-42cb-a991-624cc082ed4d", + "type": "hardware", + "title": "[SAMPLE]Product", + "description": "FUNCTION: Describe typical component function.", + "props": [ + { + "name": "asset-type", + "value": "database" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "database" + }, + { + "name": "vendor-name", + "value": "Vendor Name" + }, + { + "name": "model", + "value": "Model Number" + }, + { + "name": "version", + "value": "Version Number" + } + ], + "status": { + "state": "operational" + }, + "responsible-roles": [ + { + "role-id": "asset-administrator", + "party-uuids": [ + "b306f5af-b93a-4a7f-a2b2-37a44fc92a79" + ] + }, + { + "role-id": "asset-owner", + "party-uuids": [ + "36b8d6c0-3b25-42cc-b529-cf4066145cdd" + ] + } + ], + "remarks": "COMMENTS: Provide other comments as needed." + }, + { + "uuid": "6617f60b-8bac-422d-9939-94f43ddc0f7a", + "type": "software", + "title": "OS Sample", + "description": "None", + "props": [ + { + "name": "asset-type", + "value": "operating-system" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + }, + { + "name": "baseline-configuration-name", + "value": "Baseline Config. Name" + }, + { + "name": "allows-authenticated-scan", + "value": "yes" + } + ], + "status": { + "state": "operational" + } + }, + { + "uuid": "120f1404-7c9f-4856-a247-63bd89d9e769", + "type": "software", + "title": "Database Sample", + "description": "None", + "props": [ + { + "name": "asset-type", + "value": "database" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "database" + }, + { + "name": "baseline-configuration-name", + "value": "Baseline Config. Name" + }, + { + "name": "allows-authenticated-scan", + "value": "yes" + } + ], + "status": { + "state": "operational" + } + }, + { + "uuid": "8f230d84-2f9b-44a3-acdb-019566ab2554", + "type": "software", + "title": "Appliance Sample", + "description": "None", + "props": [ + { + "name": "asset-type", + "value": "appliance" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "web" + }, + { + "name": "login-url", + "ns": "https://fedramp.gov/ns/oscal", + "value": "https://admin.offering.com/login" + }, + { + "name": "baseline-configuration-name", + "value": "Baseline Config. Name" + }, + { + "name": "allows-authenticated-scan", + "value": "no", + "remarks": "Vendor appliance. No admin-level access." + } + ], + "status": { + "state": "operational" + } + }, + { + "uuid": "88b8d7bb-ba23-4430-bf62-028eab822050", + "type": "policy", + "title": "[EXAMPLE]Policies", + "description": "[EXAMPLE]component representing a collection of policies in appendix A.", + "links": [ + { + "href": "#330bac69-5840-479a-981b-afda037d7a6f", + "rel": "policy" + }, + { + "href": "#184d2fc9-6c9e-4302-acb3-8c24f6843c79", + "rel": "policy" + }, + { + "href": "#64977a9e-cd62-4c04-891e-7943e9046179", + "rel": "policy" + }, + { + "href": "#f81fe324-844f-4b53-b915-8c72b6fde8cf", + "rel": "policy" + }, + { + "href": "#eb4467a5-c3ca-4cac-9181-557886d7d1dc", + "rel": "policy" + }, + { + "href": "#4c4395c5-a126-4b77-8c62-cac98c563915", + "rel": "policy" + }, + { + "href": "#f6070655-ac54-4c4c-847e-d073bcf23baf", + "rel": "policy" + }, + { + "href": "#e39a9f53-984b-429f-a062-a815228c6687", + "rel": "policy" + }, + { + "href": "#8b009787-771c-4b02-9a8f-3f3b581e9464", + "rel": "policy" + }, + { + "href": "#776b9f3b-2896-4118-87d9-7a5e62149afb", + "rel": "policy" + }, + { + "href": "#a54bc32c-6bae-4c89-b5b4-9299c56893fb", + "rel": "policy" + }, + { + "href": "#9de28452-4b02-4b49-b316-59142a7633c1", + "rel": "policy" + }, + { + "href": "#34f3388e-e5b2-4d85-b050-19f62dba6d7e", + "rel": "policy" + }, + { + "href": "#53fbc1b6-0f3c-4298-9554-da5acfef3a5a", + "rel": "policy" + }, + { + "href": "#f969f849-8920-4325-9abe-dcc7133518d6", + "rel": "policy" + }, + { + "href": "#03ae437f-fffc-48e3-81f1-4040fce2d6e3", + "rel": "policy" + }, + { + "href": "#7a5ee0b7-402c-487f-8ac7-e1735b991674", + "rel": "policy" + } + ], + "status": { + "state": "operational" + }, + "remarks": "Links to the components, attached as a `resource` in `back-matter`." + }, + { + "uuid": "fa90644a-8bf8-47da-b0d3-82bffc708afc", + "type": "procedure", + "title": "[EXAMPLE]Procedures", + "description": "[EXAMPLE]component representing a collection of procedures in appendix A.", + "links": [ + { + "href": "#e1fa7a30-efb8-4738-b4e2-7fbeb86644cd", + "rel": "procedure" + }, + { + "href": "#ce9f3af2-f4bc-47b5-bc25-df52a917748b", + "rel": "procedure" + }, + { + "href": "#b1cdaad8-2127-4563-b248-3d2777307c4f", + "rel": "procedure" + }, + { + "href": "#a552272e-803c-40db-895c-5de35c76d871", + "rel": "procedure" + }, + { + "href": "#b4c87da0-0f96-4231-a3c1-2d1a9d0b99a3", + "rel": "procedure" + }, + { + "href": "#2f1cb360-a743-4ebe-915a-27f215f44dc5", + "rel": "procedure" + }, + { + "href": "#08a6ab70-8c56-4713-ae9c-81fbb6594943", + "rel": "procedure" + }, + { + "href": "#649eac51-c21b-4cb2-bd10-7828e0522e50", + "rel": "procedure" + }, + { + "href": "#fd29a63b-2a08-4d56-b91e-aadfa4c0f55b", + "rel": "procedure" + }, + { + "href": "#908175c9-7502-4ab4-b469-80450ed18a8b", + "rel": "procedure" + }, + { + "href": "#22522abe-fd09-4476-b09f-c6422b72bf12", + "rel": "procedure" + }, + { + "href": "#937dfbb6-9d82-4974-be85-23f1e4b130d8", + "rel": "procedure" + }, + { + "href": "#552dec25-74a9-4cbe-b3b0-f865d99bfa9d", + "rel": "procedure" + }, + { + "href": "#1a852337-d28f-4a66-a367-68aebec35698", + "rel": "procedure" + }, + { + "href": "#4a59a06d-3b1b-410f-b067-3fe1dab083f2", + "rel": "procedure" + }, + { + "href": "#936093ce-a567-4592-8fcc-eeeef024cdd4", + "rel": "procedure" + }, + { + "href": "#ac953d62-a392-499f-b832-b90b325cceb6", + "rel": "procedure" + } + ], + "status": { + "state": "operational" + }, + "remarks": "Links to the components, attached as a `resource` in `back-matter`." + }, + { + "uuid": "d5841417-de4c-4d84-ab3c-39dd1fd32a96", + "type": "service", + "title": "[SAMPLE]Service Name", + "description": "Describe the service", + "purpose": "Describe the reason the service is needed.", + "links": [ + { + "href": "60f92bcf-f353-4236-9803-2a5d417555f4", + "rel": "used-by" + }, + { + "href": "77A1614A-57B3-4B32-9FEE-613A6520EC58", + "rel": "provided-by" + } + ], + "status": { + "state": "operational" + }, + "protocols": [ + { + "uuid": "653ad9b9-9c78-4bc0-8a93-6ebd3c0fce54", + "name": "http", + "port-ranges": [ + { + "start": 80, + "end": 80, + "transport": "TCP" + } + ] + }, + { + "uuid": "3ac9b137-479e-47d4-bc7e-aaa97c76aa63", + "name": "https", + "port-ranges": [ + { + "start": 443, + "end": 443, + "transport": "TCP" + } + ] + } + ], + "remarks": "Section 10.2, Table 10-1. Ports, Protocols and Services\n\n **SERVICES ARE NOW COMPONENTS WITH type='service'** " + }, + { + "uuid": "2812ef51-61e7-4505-afbb-da5a073a2a5b", + "type": "interconnection", + "title": "[EXAMPLE]Authorized Connection Information System Name", + "description": "Briefly describe the interconnection.", + "props": [ + { + "name": "service-processor", + "ns": "https://fedramp.gov/ns/oscal", + "value": "[SAMPLE] Telco Name" + }, + { + "name": "ipv4-address", + "value": "10.1.1.1", + "class": "local" + }, + { + "name": "ipv4-address", + "value": "10.2.2.2", + "class": "remote" + }, + { + "name": "ipv6-address", + "value": "2001:0000:0000:0000:0000:ffff:0a02:0202" + }, + { + "name": "direction", + "value": "incoming" + }, + { + "name": "direction", + "value": "outgoing" + }, + { + "name": "information", + "ns": "https://fedramp.gov/ns/oscal", + "value": "Describe the information being transmitted." + }, + { + "name": "port", + "ns": "https://fedramp.gov/ns/oscal", + "value": "80", + "class": "remote" + }, + { + "name": "interconnection-security", + "ns": "https://fedramp.gov/ns/oscal", + "value": "ipsec", + "remarks": "If \\\"other\\\", remarks are required. Optional otherwise." + } + ], + "links": [ + { + "href": "#9d6cf2b4-8e88-4040-a33c-7bc206553a1a", + "rel": "isa-agreement" + } + ], + "status": { + "state": "operational" + }, + "responsible-roles": [ + { + "role-id": "isa-poc-remote", + "party-uuids": [ + "09ad840f-aa79-43aa-9f22-25182c2ab11b" + ] + }, + { + "role-id": "isa-poc-local", + "party-uuids": [ + "09ad840f-aa79-43aa-9f22-25182c2ab11b" + ] + }, + { + "role-id": "isa-authorizing-official-remote", + "party-uuids": [ + "09ad840f-aa79-43aa-9f22-25182c2ab11b" + ] + }, + { + "role-id": "isa-authorizing-official-local", + "party-uuids": [ + "09ad840f-aa79-43aa-9f22-25182c2ab11b" + ] + } + ], + "remarks": "Optional notes about this interconnection" + }, + { + "uuid": "55b55b3d-3bd9-409a-bc87-3b9a2074bacd", + "type": "network", + "title": "IPv4 Production Subnet", + "description": "IPv4 Production Subnet.", + "status": { + "state": "operational" + } + }, + { + "uuid": "c0dbefa1-c8e8-4ca8-bd73-67cb7b1fa3f6", + "type": "network", + "title": "IPv4 Management Subnet", + "description": "IPv4 Management Subnet.", + "status": { + "state": "operational" + } + }, + { + "uuid": "60f92bcf-f353-4236-9803-2a5d417555f5", + "type": "service", + "title": "Email Service", + "description": "Email Service", + "links": [ + { + "href": "60f92bcf-f353-4236-9803-2a5d417555f4", + "rel": "used-by" + } + ], + "status": { + "state": "operational" + } + } + ], + "inventory-items": [ + { + "uuid": "98e37f90-fbb5-4177-badb-9b55229cc183", + "description": "Legacy Example (No implemented-component).", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-1" + }, + { + "name": "ipv4-address", + "value": "10.1.1.1" + }, + { + "name": "ipv6-address", + "value": "2001:db8:3333:4444:5555:6666:7777:8888" + }, + { + "name": "virtual", + "value": "no" + }, + { + "name": "public", + "value": "no" + }, + { + "name": "fqdn", + "value": "dns.name" + }, + { + "name": "uri", + "value": "uniform.resource.identifier" + }, + { + "name": "netbios-name", + "value": "netbios-name" + }, + { + "name": "mac-address", + "value": "00:00:00:00:00:00" + }, + { + "name": "software-name", + "value": "software-name" + }, + { + "name": "asset-type", + "value": "operating-system" + }, + { + "name": "serial-number", + "value": "Serial #" + }, + { + "name": "asset-tag", + "value": "Asset Tag" + }, + { + "name": "vlan-id", + "value": "VLAN Identifier" + }, + { + "name": "network-id", + "value": "Network Identifier" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + }, + { + "name": "allows-authenticated-scan", + "value": "no", + "remarks": "If no, explain why. If yes, omit remarks field." + }, + { + "name": "baseline-configuration-name", + "value": "Baseline Config. Name" + }, + { + "name": "physical-location", + "value": "Physical location of Asset" + }, + { + "name": "is-scanned", + "value": "yes", + "remarks": "If no, explain why. If yes, omit remarks field." + }, + { + "name": "function", + "value": "Required brief, text-based description.", + "remarks": "Optional, longer, formatted description." + } + ], + "links": [ + { + "href": "#95beec7e-6f82-4aaa-8211-969cd7c1f1ab", + "rel": "validation" + } + ], + "responsible-parties": [ + { + "role-id": "asset-owner", + "party-uuids": [ + "db234cb7-1776-425c-9ac4-b067c1723011" + ] + }, + { + "role-id": "asset-administrator", + "party-uuids": [ + "b306f5af-b93a-4a7f-a2b2-37a44fc92a79" + ] + } + ], + "implemented-components": [ + { + "component-uuid": "05ceb8df-52e7-49db-9719-891723f366bd", + "remarks": "This links to a FIPS 140-2 validated software component that is used by this inventory item. This type of linkage to a validation through the component is preferable to the link[rel='validation'] example above." + } + ], + "remarks": "COMMENTS: Additional information about this item." + }, + { + "uuid": "c916d3c5-229e-4786-bf3f-4d71baa0e7a5", + "description": "Component Inventory Example", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-2" + }, + { + "name": "ipv4-address", + "value": "10.2.2.2" + }, + { + "name": "ipv6-address", + "value": "0000:0000:0000:0000:0000:ffff:0a02:0202" + }, + { + "name": "mac-address", + "value": "00:00:00:00:00:00" + }, + { + "name": "asset-type", + "value": "appliance" + }, + { + "name": "virtual", + "value": "no" + }, + { + "name": "public", + "value": "no" + }, + { + "name": "fqdn", + "value": "dns.name" + }, + { + "name": "uri", + "value": "uniform.resource.locator" + }, + { + "name": "netbios-name", + "value": "netbios-name" + }, + { + "name": "baseline-configuration-name", + "value": "Baseline Configuration Name" + }, + { + "name": "physical-location", + "value": "Physical location of Asset" + }, + { + "name": "allows-authenticated-scan", + "value": "no", + "remarks": "If no, explain why. If yes, omit remark." + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + } + ], + "responsible-parties": [ + { + "role-id": "asset-owner", + "party-uuids": [ + "3360e343-9860-4bda-9dfc-ff427c3dfab6" + ] + }, + { + "role-id": "asset-administrator", + "party-uuids": [ + "b306f5af-b93a-4a7f-a2b2-37a44fc92a79" + ] + } + ], + "implemented-components": [ + { + "component-uuid": "05ceb8df-52e7-49db-9719-891723f366bd", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-3" + } + ] + } + ], + "remarks": "COMMENTS: If needed, provide additional information about this inventory item." + }, + { + "uuid": "37c00d5a-ccf2-4112-a0ee-8460be8cff40", + "description": "None.", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-4" + }, + { + "name": "asset-type", + "value": "web-server" + }, + { + "name": "virtual", + "value": "yes" + }, + { + "name": "public", + "value": "no" + }, + { + "name": "ipv4-address", + "value": "10.3.3.3" + }, + { + "name": "ipv6-address", + "value": "0000:0000:0000:0000:0000:ffff:0a03:0303" + }, + { + "name": "is-scanned", + "value": "yes" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + } + ], + "implemented-components": [ + { + "component-uuid": "1541015b-6d19-42cb-a991-624cc082ed4d" + } + ] + }, + { + "uuid": "fb7a84fb-7e30-4f5b-9997-2ecd4d270bdd", + "description": "None.", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-5" + }, + { + "name": "asset-type", + "value": "appliance" + }, + { + "name": "virtual", + "value": "yes" + }, + { + "name": "public", + "value": "no" + }, + { + "name": "ipv4-address", + "value": "10.4.4.4" + }, + { + "name": "ipv6-address", + "value": "0000:0000:0000:0000:0000:ffff:0a04:0404" + }, + { + "name": "is-scanned", + "value": "yes" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + } + ], + "implemented-components": [ + { + "component-uuid": "05ceb8df-52e7-49db-9719-891723f366bd" + } + ] + }, + { + "uuid": "779d4e89-bba6-432c-b50d-d699fe534129", + "description": "None.", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-6" + }, + { + "name": "asset-type", + "value": "firewall" + }, + { + "name": "ipv4-address", + "value": "10.5.5.5" + }, + { + "name": "ipv6-address", + "value": "0000:0000:0000:0000:0000:ffff:0a05:0505" + }, + { + "name": "virtual", + "value": "no" + }, + { + "name": "public", + "value": "yes" + }, + { + "name": "is-scanned", + "value": "yes" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + } + ], + "implemented-components": [ + { + "component-uuid": "8f230d84-2f9b-44a3-acdb-019566ab2554" + } + ] + }, + { + "uuid": "20b207d5-5e77-4501-b02d-5d2a6e88db85", + "description": "None.", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-7" + }, + { + "name": "ipv4-address", + "value": "10.6.6.6" + }, + { + "name": "ipv6-address", + "value": "0000:0000:0000:0000:0000:ffff:0a06:0606" + }, + { + "name": "asset-type", + "value": "router" + }, + { + "name": "virtual", + "value": "no" + }, + { + "name": "public", + "value": "no" + }, + { + "name": "is-scanned", + "value": "no", + "remarks": "Asset wasn't running at time of scan." + } + ], + "implemented-components": [ + { + "component-uuid": "05ceb8df-52e7-49db-9719-891723f366bd" + } + ] + }, + { + "uuid": "79b4f0d1-91ab-49e8-af28-045c12aa9272", + "description": "None.", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-8" + }, + { + "name": "asset-type", + "value": "switch" + }, + { + "name": "ipv4-address", + "value": "10.7.7.7" + }, + { + "name": "ipv6-address", + "value": "0000:0000:0000:0000:0000:ffff:0a07:0707" + }, + { + "name": "virtual", + "value": "no" + }, + { + "name": "public", + "value": "no" + }, + { + "name": "is-scanned", + "value": "yes" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + } + ], + "implemented-components": [ + { + "component-uuid": "1541015b-6d19-42cb-a991-624cc082ed4d" + } + ] + }, + { + "uuid": "b31b360d-b58b-4c7c-b344-68e17238d858", + "description": "None.", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-9" + }, + { + "name": "asset-type", + "value": "web-server" + }, + { + "name": "ipv4-address", + "value": "10.8.8.8" + }, + { + "name": "ipv6-address", + "value": "0000:0000:0000:0000:0000:ffff:0a08:0808" + }, + { + "name": "virtual", + "value": "yes" + }, + { + "name": "public", + "value": "no" + }, + { + "name": "is-scanned", + "value": "no", + "remarks": "Asset wasn't running at time of scan." + } + ], + "implemented-components": [ + { + "component-uuid": "05ceb8df-52e7-49db-9719-891723f366bd" + } + ] + }, + { + "uuid": "13c94c20-e4c4-44ee-bbbf-3d14fb01cb18", + "description": "Email-Service", + "props": [ + { + "name": "asset-id", + "value": "unique-asset-ID-10" + }, + { + "name": "asset-type", + "value": "email-server" + }, + { + "name": "ipv4-address", + "value": "10.10.10.100" + }, + { + "name": "ipv6-address", + "value": "0000:0000:0000:0000:0000:ffff:0a08:0808" + }, + { + "name": "virtual", + "value": "yes" + }, + { + "name": "public", + "value": "no" + }, + { + "name": "is-scanned", + "value": "yes" + }, + { + "name": "scan-type", + "ns": "https://fedramp.gov/ns/oscal", + "value": "infrastructure" + } + ], + "implemented-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f5" + } + ] + } + ] + }, + "control-implementation": { + "description": "Appendix A - FedRAMP SSP Rev5 Template\n\nThis description field is required by OSCAL.\n\nFedRAMP does not require any specific information here.", + "implemented-requirements": [ + { + "uuid": "eee8697a-bc39-45aa-accc-d3e534932efb", + "control-id": "ac-1", + "set-parameters": [ + { + "param-id": "ac-1_prm_1", + "values": [ + "organization-defined personnel or roles" + ] + }, + { + "param-id": "ac-01_odp.05", + "values": [ + "at least every 3 years" + ] + }, + { + "param-id": "ac-01_odp.07", + "values": [ + "at least annually" + ] + } + ], + "props": [ + { + "name": "planned-completion-date", + "ns": "https://fedramp.gov/ns/oscal", + "value": "2024-01-31Z" + }, + { + "name": "implementation-status", + "ns": "https://fedramp.gov/ns/oscal", + "value": "planned", + "remarks": "Describe the plan to complete the implementation." + }, + { + "name": "control-origination", + "ns": "https://fedramp.gov/ns/oscal", + "value": "sp-system" + } + ], + "links": [ + { + "href": "#330bac69-5840-479a-981b-afda037d7a6f", + "rel": "policy" + }, + { + "href": "#e1fa7a30-efb8-4738-b4e2-7fbeb86644cd", + "rel": "procedure" + } + ], + "statements": [ + { + "statement-id": "ac-1_smt", + "uuid": "240fa015-01df-4741-bff5-6958c7fb85e5", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "d9d1ce66-ff47-474d-8596-5fdf2af60179", + "description": "Describe how the control is satisfied within the system." + } + ] + }, + { + "statement-id": "ac-1_smt.a", + "uuid": "fb4d039a-dc4f-46f5-9c1f-f6343eaf69bc", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "3f5612a4-cd1d-4c47-8cae-75d2eaa332cd", + "description": "Describe how Part a is satisfied within the system.", + "links": [ + { + "href": "#330bac69-5840-479a-981b-afda037d7a6f", + "rel": "policy" + }, + { + "href": "#e1fa7a30-efb8-4738-b4e2-7fbeb86644cd", + "rel": "procedure" + } + ], + "remarks": "The specified component is the system itself.\n\nAny control implementation response that can not be associated with another component is associated with the component representing the system." + }, + { + "component-uuid": "88b8d7bb-ba23-4430-bf62-028eab822050", + "uuid": "2CF56836-6834-49A9-96CD-4F49C17AAB01", + "description": "Describe how this policy component satisfies part a." + } + ] + }, + { + "statement-id": "ac-1_smt.b", + "uuid": "c365cf95-5bc0-4599-9773-f4eddf69798d", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "00507a44-e0d7-4fe6-ad20-8d474a84ee15", + "description": "Describe how Part b is satisfied within the system for a component." + }, + { + "component-uuid": "fa90644a-8bf8-47da-b0d3-82bffc708afc", + "uuid": "42ac379e-4abc-4716-809c-119c03b5ac64", + "description": "Describe how Part b is satisfied within the system for another component." + } + ] + }, + { + "statement-id": "ac-1_smt.b.1", + "uuid": "b46f97ec-55c1-4249-a9b9-3a228f1e3791", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "767666cb-e558-484b-81ca-b0209932425c", + "description": "Describe how Part b-1 is satisfied." + } + ] + }, + { + "statement-id": "ac-1_smt.b.2", + "uuid": "59c67969-3d5c-45f1-8e3e-1e642249633f", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "5a869308-1625-4d92-9ed8-ff5d8bd13656", + "description": "Describe how Part b-2 is satisfied." + } + ] + } + ] + }, + { + "uuid": "7a36cf53-156d-4d1f-9a8b-433f61cc57b7", + "control-id": "ac-2", + "props": [ + { + "name": "planned-completion-date", + "ns": "https://fedramp.gov/ns/oscal", + "value": "2024-01-31Z" + }, + { + "name": "implementation-status", + "ns": "https://fedramp.gov/ns/oscal", + "value": "implemented", + "remarks": "Describe the plan to complete the implementation." + }, + { + "name": "control-origination", + "ns": "https://fedramp.gov/ns/oscal", + "value": "sp-system" + }, + { + "name": "control-origination", + "ns": "https://fedramp.gov/ns/oscal", + "value": "customer-configured", + "remarks": "Describe any customer-configured requirements for satisfying this control." + } + ], + "responsible-roles": [ + { + "role-id": "admin-unix", + "party-uuids": [ + "3360e343-9860-4bda-9dfc-ff427c3dfab6" + ] + }, + { + "role-id": "information-system-security-officer", + "party-uuids": [ + "36b8d6c0-3b25-42cc-b529-cf4066145cdd" + ] + } + ], + "statements": [ + { + "statement-id": "ac-2_smt", + "uuid": "4a2428eb-41eb-447a-81db-4f6d98a003ce", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "eb710146-1ede-4876-9a3b-02c18408e506", + "description": "Describe how the control is satisfied within the system.", + "set-parameters": [ + { + "param-id": "ac-2_prm_1", + "values": [ + "[SAMPLE]privileged, non-privileged" + ] + }, + { + "param-id": "ac-2_prm_2", + "values": [ + "[SAMPLE]all" + ] + }, + { + "param-id": "ac-2_prm_3", + "values": [ + "[SAMPLE]The Access Control Procedure" + ] + }, + { + "param-id": "ac-2_prm_4", + "values": [ + "at least annually" + ] + } + ] + } + ] + }, + { + "statement-id": "ac-2_smt.a", + "uuid": "24a85abb-25ad-4686-850c-5c0e8ab69a0c", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "b29d1505-69fa-4ad0-834b-d179e7f44f98", + "description": "Describe how AC-2, part a is satisfied within this system.\n\nThis points to the \\\"This System\\\" component, and is used any time a more specific component reference is not available.", + "export": { + "provided": [ + { + "uuid": "b068e08a-53b9-4f80-ac5f-0476c35c6e46", + "description": "Leveraged system's statement of capabilities which may be inherited by a leveraging systems to satisfy AC-2, part a." + } + ], + "responsibilities": [ + { + "uuid": "39e5b068-deb7-4f93-9a32-2dcce15b1107", + "provided-uuid": "b068e08a-53b9-4f80-ac5f-0476c35c6e46", + "description": "Leveraged system's statement of a leveraging system's responsibilities in satisfaction of AC-2, part a.\n\nNot associated with inheritance, thus associated this with the by-component for \\\"this system\\\".", + "responsible-roles": [ + { + "role-id": "cloud-service-provider", + "party-uuids": [ + "6b286b5d-8f07-4fa7-8847-1dd0d88f73fb" + ] + } + ] + } + ] + } + }, + { + "component-uuid": "d5841417-de4c-4d84-ab3c-39dd1fd32a96", + "uuid": "8a72663c-28c7-41c2-8739-f1ee2d5761ac", + "description": "For the portion of the control satisfied by the application component of this system, describe **how** the control is met.", + "export": { + "provided": [ + { + "uuid": "11111111-0000-4000-9009-002001002001", + "description": "Consumer-appropriate description of what may be inherited from this application component by a leveraging system.\n\nIn the context of the application component in satisfaction of AC-2, part a.", + "responsible-roles": [ + { + "role-id": "customer", + "party-uuids": [ + "f595397b-cbe4-4a87-8c86-9bff91c4e7fd" + ] + } + ] + } + ], + "responsibilities": [ + { + "uuid": "11111111-0000-4000-9009-002001002002", + "provided-uuid": "11111111-0000-4000-9009-002001002001", + "description": "Leveraging system's responsibilities with respect to inheriting this capability from this application.\n\nIn the context of the application component in satisfaction of AC-2, part a.", + "responsible-roles": [ + { + "role-id": "customer", + "party-uuids": [ + "f595397b-cbe4-4a87-8c86-9bff91c4e7fd" + ] + } + ] + } + ] + }, + "remarks": "The component-uuid above points to the \\\"this system\\\" component.\n\nAny control response content that does not cleanly fit another system component is placed here. This includes customer responsibility content.\n\nThis can also be used to provide a summary, such as a holistic overview of how multiple components work together.\n\nWhile the \\\"this system\\\" component is not explicitly required within every `statement`, it will typically be present." + }, + { + "component-uuid": "e82e6e07-0c62-417e-8a19-3744991b4c65", + "uuid": "84de735f-ba37-4bb4-b784-79760f986a40", + "description": "For the portion inherited from an underlying FedRAMP-authorized provider, describe **what** is inherited.", + "inherited": [ + { + "uuid": "780A3910-2019-4D33-A2F9-5C6AC91929D6", + "provided-uuid": "11111111-0000-4000-9009-002001002001", + "description": "Optional description.\n\nConsumer-appropriate description of what may be inherited as provided by the leveraged system.\n\nIn the context of this component in satisfaction of AC-2, part a.\n\nThe `provided-uuid` links this to the same statement in the leveraged system's SSP.\n\nIt may be linked directly, but is more commonly provided via an OSCAL-based CRM (Inheritance and Responsibility Model)." + } + ], + "satisfied": [ + { + "uuid": "6486F725-1372-434F-9B1B-7CF3F50C32D1", + "responsibility-uuid": "11111111-0000-4000-9009-002001002002", + "description": "Description of how the responsibility was satisfied.\n\nThe `responsibility-uuid` links this to the same statement in the leveraged system's SSP.\n\nIt may be linked directly, but is more commonly provided via an OSCAL-based CRM (Inheritance and Responsibility Model).\n\nTools should use this to ensure all identified customer `responsibility` statements have a corresponding `satisfied` statement in the leveraging system's SSP.\n\nTool developers should be mindful that " + } + ] + } + ] + } + ] + }, + { + "uuid": "381c8d0c-e6ec-41a9-9b16-01657226c70f", + "control-id": "au-1", + "props": [ + { + "name": "planned-completion-date", + "ns": "https://fedramp.gov/ns/oscal", + "value": "2024-01-31Z" + }, + { + "name": "implementation-status", + "ns": "https://fedramp.gov/ns/oscal", + "value": "partial", + "remarks": "Describe the plan to complete the implementation." + }, + { + "name": "control-origination", + "ns": "https://fedramp.gov/ns/oscal", + "value": "sp-corporate" + } + ], + "links": [ + { + "href": "#64977a9e-cd62-4c04-891e-7943e9046179", + "rel": "policy" + }, + { + "href": "#b1cdaad8-2127-4563-b248-3d2777307c4f", + "rel": "procedure" + } + ], + "responsible-roles": [ + { + "role-id": "information-system-security-officer", + "party-uuids": [ + "36b8d6c0-3b25-42cc-b529-cf4066145cdd" + ] + } + ], + "set-parameters": [ + { + "param-id": "au-1_prm_1", + "values": [ + "organization-defined personnel or roles" + ] + }, + { + "param-id": "au-01_odp.05", + "values": [ + "at least every 3 years" + ] + }, + { + "param-id": "au-01_odp.07", + "values": [ + "at least annually" + ] + } + ], + "statements": [ + { + "statement-id": "au-1_smt", + "uuid": "a9a883f4-f550-4f11-941a-2eb9ce9c3faf", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "e985ae45-6ab4-4f12-8699-3ebf87e35bd5", + "description": "Describe how the control is satisfied within the system." + } + ] + }, + { + "statement-id": "au-1_smt.a", + "uuid": "9a2bd937-226e-4aaf-8261-2cf0c2e3aa10", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "30042cb9-ff85-472f-b769-68bd7bb5bbd9", + "description": "For the portion of the control satisfied by the service provider, describe **how** the control is met.", + "links": [ + { + "href": "#64977a9e-cd62-4c04-891e-7943e9046179", + "rel": "policy" + } + ] + }, + { + "component-uuid": "88b8d7bb-ba23-4430-bf62-028eab822050", + "uuid": "d3fca6df-63b7-4b73-b49c-c954e73c7ddb", + "description": "Describe how this policy component satisfies part a.\n\nComponent approach. This links to a component representing the Policy.\n\nThat component contains a link to the policy, so it does not have to be linked here too." + }, + { + "component-uuid": "fa90644a-8bf8-47da-b0d3-82bffc708afc", + "uuid": "34cc172b-e868-4570-9947-c86b3612f2fb", + "description": "Describe how this procedure component satisfies part a.\n\nComponent approach. This links to a component representing the procedure.\n\nThat component contains a link to the procedure, so it does not have to be linked here too." + } + ] + }, + { + "statement-id": "au-1_smt.b.1", + "uuid": "d01f186f-a14f-4e22-b069-84a55e48a112", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "f41962c7-b53b-46f8-a84f-4aba25904bb8", + "description": "For the portion of the control satisfied by the service provider, describe **how** the control is met.", + "links": [ + { + "href": "#64977a9e-cd62-4c04-891e-7943e9046179", + "rel": "policy" + } + ] + } + ] + }, + { + "statement-id": "au-1_smt.b.2", + "uuid": "ea153acb-2bd0-41d9-8ebd-ba022d31230a", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "9ad59f0d-17a2-4f3f-af6a-a8529d692195", + "description": "For the portion of the control satisfied by the service provider, describe **how** the control is met.", + "links": [ + { + "href": "#64977a9e-cd62-4c04-891e-7943e9046179", + "rel": "policy" + } + ] + } + ] + } + ] + }, + { + "uuid": "9e2852c6-f48a-47b2-9ea5-77cbbb42b365", + "control-id": "sc-1", + "props": [ + { + "name": "planned-completion-date", + "ns": "https://fedramp.gov/ns/oscal", + "value": "2024-01-31Z" + }, + { + "name": "implementation-status", + "ns": "https://fedramp.gov/ns/oscal", + "value": "implemented", + "remarks": "Describe the plan to complete the implementation." + }, + { + "name": "control-origination", + "ns": "https://fedramp.gov/ns/oscal", + "value": "sp-system" + } + ], + "links": [ + { + "href": "#03ae437f-fffc-48e3-81f1-4040fce2d6e3", + "rel": "policy" + }, + { + "href": "#936093ce-a567-4592-8fcc-eeeef024cdd4", + "rel": "procedure" + } + ], + "responsible-roles": [ + { + "role-id": "information-system-security-officer", + "party-uuids": [ + "36b8d6c0-3b25-42cc-b529-cf4066145cdd" + ] + } + ], + "statements": [ + { + "statement-id": "sc-1_smt", + "uuid": "3f1307fa-7405-42ea-a9ad-61b7a94bc704", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "8c52b949-a7ad-4bef-9da2-b342cef3dc45", + "description": "Describe how the control is satisfied within the system.", + "set-parameters": [ + { + "param-id": "sc-1_prm_1", + "values": [ + "organization-defined personnel or roles" + ] + }, + { + "param-id": "sc-1_prm_2", + "values": [ + "at least every 3 years" + ] + }, + { + "param-id": "sc-1_prm_3", + "values": [ + "at least annually" + ] + } + ] + } + ] + }, + { + "statement-id": "sc-1_smt.a", + "uuid": "5e2e8372-c13b-4cf5-90c5-e8833a9fe241", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "88cfadba-043b-483b-8032-73344aa53c96", + "description": "For the portion of the control satisfied by the service provider, describe **how** the control is met." + }, + { + "component-uuid": "88b8d7bb-ba23-4430-bf62-028eab822050", + "uuid": "7a673b8a-4c21-49b0-89bd-216753af6bbc", + "description": "Describe how this policy component satisfies part a.\n\nComponent approach. This links to a component representing the Policy.\n\nThat component contains a link to the policy, so it does not have to be linked here too." + }, + { + "component-uuid": "fa90644a-8bf8-47da-b0d3-82bffc708afc", + "uuid": "b1b50bf8-58ae-4e93-a5f6-b6f0b8b1d7af", + "description": "Describe how this procedure component satisfies part a.\n\nComponent approach. This links to a component representing the procedure.\n\nThat component contains a link to the procedure, so it does not have to be linked here too." + } + ] + }, + { + "statement-id": "sc-1_smt.b.1", + "uuid": "8166980a-86c0-497d-87e4-453adfd0d4bd", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "9abaeb64-56d2-48a1-bd8d-7b55411d31ca", + "description": "For the portion of the control satisfied by the service provider, describe **how** the control is met." + } + ] + }, + { + "statement-id": "sc-1_smt.b.2", + "uuid": "eeea34ff-18ab-4c35-bf32-c74dbf746e7b", + "by-components": [ + { + "component-uuid": "60f92bcf-f353-4236-9803-2a5d417555f4", + "uuid": "ad20ff50-8a7c-4ffc-a918-260960f6fb42", + "description": "For the portion of the control satisfied by the service provider, describe **how** the control is met." + } + ] + } + ] + } + ] + }, + "back-matter": {} + } +} diff --git a/tests/test_utils.py b/tests/test_utils.py index c040800..ba61530 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -16,6 +16,14 @@ """Test utils module.""" import pathlib +from typing import Dict, List, Tuple + +from docx.table import Table, _Cell # type: ignore +from docx.text.paragraph import Paragraph # type: ignore + +from trestle_fedramp import const +from trestle_fedramp.core.docx_helper import ControlImplementationDescriptions, ControlSummaries +from trestle_fedramp.core.ssp_reader import FedrampSSPData JSON_FEDRAMP_SAR_PATH = pathlib.Path('fedramp-source/dist/content/rev5/templates/sar/json/').resolve() JSON_FEDRAMP_SAR_NAME = 'FedRAMP-SAR-OSCAL-Template.json' @@ -23,3 +31,107 @@ JSON_FEDRAMP_SSP_NAME = 'FedRAMP-SSP-OSCAL-Template.json' XML_FEDRAMP_SSP_PATH = pathlib.Path('fedramp-source/dist/content/rev5/templates/ssp/xml/').resolve() XML_FEDRAMP_SSP_NAME = 'FedRAMP-SSP-OSCAL-Template.xml' +JSON_TEST_DATA_PATH = pathlib.Path('tests/data/json/').resolve() +TEST_SSP_JSON = 'simplified_fedramp_ssp_template.json' + + +def verify_control_origination_checkboxes(cell: _Cell, ssp_data: FedrampSSPData) -> None: + """Verify the control origination checkboxes are populated correctly.""" + checked_list, checked_list_text = get_checked_list(cell) + if ssp_data.control_origination is None: + assert len(checked_list) == 0 + else: + expected_checklist_list: List[int] = [] + control_summaries = ControlSummaries() + for control_origination in ssp_data.control_origination: + index_loc: int = control_summaries.get_control_origination_index(control_origination) + expected_checklist_list.append(index_loc) + + # Check that the actual text is correct in the paragraph + # Each FedRAMP long string should be in the checked paragraphs of the + # cell. + assert control_origination in checked_list_text + + assert checked_list == expected_checklist_list + + +def verify_implementation_status_checkboxes(cell: _Cell, ssp_data: FedrampSSPData) -> None: + """Verify the implementation status checkboxes are populated correctly.""" + checked_list, checked_list_text = get_checked_list(cell) + if ssp_data.implementation_status is None: + assert len(checked_list) == 0 + else: + control_summaries = ControlSummaries() + implementation_status = control_summaries.get_implementation_status_index(ssp_data.implementation_status) + + assert checked_list == [implementation_status] + + # Verify the text is what is expected + assert ssp_data.implementation_status in checked_list_text + + +def get_checked_list(cell: _Cell) -> Tuple[List[int], str]: + """Get the checked list.""" + checked_list: List[int] = [] + checked_list_text: str = '' + for i, paragraph in enumerate(cell.paragraphs): + if checkbox_is_set(paragraph) and checkbox_text_is_set(paragraph): + checked_list.append(i) + checked_list_text += paragraph.text + return checked_list, checked_list_text + + +def checkbox_is_set(paragraph: Paragraph) -> bool: + """Get the checkbox value.""" + checkboxes = paragraph._element.xpath(const.CHECKBOX_XPATH) + if checkboxes: + checkbox = checkboxes[0] + checked = checkbox.find(f'{const.XML_NAMESPACE}checked') + return checked.attrib[f'{const.XML_NAMESPACE}val'] == '1' + return False + + +def checkbox_text_is_set(paragraph: Paragraph) -> bool: + """Get the checkbox text value.""" + checkboxes = paragraph._element.xpath(const.BOX_ICON_XPATH) + if checkboxes: + checkbox = checkboxes[0] + return checkbox.text == const.CHECKED_BOX_ICON + return False + + +def verify_responses(implementation_table: Table, responses: Dict[str, str], partial_match: bool = False) -> None: + """Verify the responses are populated correctly.""" + for row in implementation_table.columns[0].cells[1:]: + label = ControlImplementationDescriptions.get_part_id(row.text) + # strip everything after newline and remove the colon. + # get_part_id retrieves the label correctly for the first part + # empty cells only + label = label.split('\n')[0].strip(':') + if label in responses: + content = responses.get(label) + if partial_match: + assert content in row.text + else: + assert content == row.text + + +def verify_parameters(summary_table: Table, parameters: Dict[str, str], partial_match: bool = False) -> None: + """Verify the responses are populated correctly.""" + for row in summary_table.columns[0].cells[2:]: + label = ControlSummaries.get_parameter_id(row.text) + if label and label in parameters: + value = parameters.get(label) + if partial_match: + assert value in row.text + else: + assert value == row.text + + +def verify_responsible_roles(responsible_roles: _Cell, ssp_data: FedrampSSPData) -> None: + """Verify the responsible roles are populated correctly.""" + if not ssp_data.responsible_roles: + assert responsible_roles.text == 'Responsible Role:' + else: + expected_roles = ', '.join(ssp_data.responsible_roles) + assert responsible_roles.text == 'Responsible Role: ' + expected_roles diff --git a/tests/trestle_fedramp/commands/transform_test.py b/tests/trestle_fedramp/commands/transform_test.py new file mode 100644 index 0000000..1fce7fd --- /dev/null +++ b/tests/trestle_fedramp/commands/transform_test.py @@ -0,0 +1,172 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Testing fedramp transform command functionality. + +This validate high level functionality of the transform command. +""" + +import argparse +import logging +import pathlib +from typing import Any, Tuple + +from docx import Document # type: ignore +from docx.document import Document as DocxDocument # type: ignore + +from tests.test_utils import verify_parameters, verify_responses + +from trestle_fedramp.commands.transform import SSPTransformCmd + +test_docx_file = 'test.docx' +example_control_implementation = 'AC-1 What is the solution and how is it implemented?' +example_control_summary = 'AC-1 Control Summary Information' + + +def test_transform_ssp_level_high( + tmp_path: pathlib.Path, + tmp_trestle_dir_with_ssp: Tuple[pathlib.Path, str], +) -> None: + """Test Fedramp SSP transform command with FedRAMP High Baseline template.""" + tmp_trestle_dir, ssp_name = tmp_trestle_dir_with_ssp + tmp_file = tmp_path / test_docx_file + args = argparse.Namespace( + ssp_name=ssp_name, + level='high', + output_file=str(tmp_file), + trestle_root=tmp_trestle_dir, + verbose=0, + components='' + ) + rc = SSPTransformCmd()._run(args) + assert rc == 0 + + assert tmp_file.exists() + + # Verify example control + expected_impl_data = { + 'a': ( + 'Part a:\nThis System: Describe how Part a is satisfied within the system.\n' + '\n[EXAMPLE]Policies: Describe how this policy component satisfies part a.\n' + ), + 'b': ( + 'Part b:\nThis System: Describe how Part b is satisfied within the system for a component.\n' + '\n[EXAMPLE]Procedures: Describe how Part b is satisfied within the system for another component.\n' + ), + 'c': 'Part c:' + } + + expected_param_data = { + 'AC-1(a)': 'Parameter AC-1(a): organization-defined personnel or roles', + 'AC-1(a)(1)': 'Parameter AC-1(a)(1):', + 'AC-1(b)': 'Parameter AC-1(b):', + 'AC-1(c)(1)-1': 'Parameter AC-1(c)(1)-1: at least every 3 years', + 'AC-1(c)(1)-2': 'Parameter AC-1(c)(1)-2:', + 'AC-1(c)(2)-1': 'Parameter AC-1(c)(2)-1: at least annually', + 'AC-1(c)(2)-2': 'Parameter AC-1(c)(2)-2:' + } + + temp_doc_output: DocxDocument = Document(str(tmp_file)) + for table in temp_doc_output.tables: + if example_control_implementation in table.cell(0, 0).text: + verify_responses(table, expected_impl_data) + if example_control_summary in table.cell(0, 0).text: + verify_parameters(table, expected_param_data) + + +def test_transform_ssp_level_moderate( + tmp_path: pathlib.Path, + tmp_trestle_dir_with_ssp: Tuple[pathlib.Path, str], +) -> None: + """ + Test Fedramp SSP transform command with FedRAMP Moderate Baseline template. + + Notes: The moderate is encompassed by the high so we only need to test the details of the + high. + """ + tmp_trestle_dir, ssp_name = tmp_trestle_dir_with_ssp + tmp_file = tmp_path / test_docx_file + args = argparse.Namespace( + ssp_name=ssp_name, + level='moderate', + output_file=str(tmp_file), + trestle_root=tmp_trestle_dir, + verbose=0, + components='' + ) + rc = SSPTransformCmd()._run(args) + assert rc == 0 + + assert tmp_file.exists() + + +def test_transform_ssp_level_low( + tmp_path: pathlib.Path, + tmp_trestle_dir_with_ssp: Tuple[pathlib.Path, str], +) -> None: + """ + Test Fedramp SSP transform command with FedRAMP Low Baseline template. + + Notes: The low is encompassed by the high so we only need to test the details of the + high. + """ + tmp_trestle_dir, ssp_name = tmp_trestle_dir_with_ssp + tmp_file = tmp_path / test_docx_file + args = argparse.Namespace( + ssp_name=ssp_name, + level='low', + output_file=str(tmp_file), + trestle_root=tmp_trestle_dir, + verbose=0, + components='' + ) + rc = SSPTransformCmd()._run(args) + assert rc == 0 + + assert tmp_file.exists() + + +def test_transform_ssp_invalid_level(tmp_path: pathlib.Path, tmp_trestle_dir: pathlib.Path, caplog: Any) -> None: + """Test fails with an invalid level.""" + args = argparse.Namespace( + ssp_name='test-ssp', + level='fake', + output_file=str(tmp_path), + trestle_root=tmp_trestle_dir, + verbose=0, + components='' + ) + rc = SSPTransformCmd()._run(args) + assert rc == 1 + + +def test_transform_missing_ssp(tmp_path: pathlib.Path, tmp_trestle_dir: pathlib.Path, caplog: Any) -> None: + """Test fails with a missing ssp.""" + args = argparse.Namespace( + ssp_name='test-ssp', + level='high', + output_file=str(tmp_path), + trestle_root=tmp_trestle_dir, + verbose=0, + components='' + ) + rc = SSPTransformCmd()._run(args) + assert rc == 1 + + assert any( + record.levelno == logging.ERROR + and 'Input ssp test-ssp does not exist in the trestle workspace.' in record.message for record in caplog.records + ) diff --git a/tests/trestle_fedramp/core/baselines_test.py b/tests/trestle_fedramp/core/baselines_test.py new file mode 100644 index 0000000..6afb0eb --- /dev/null +++ b/tests/trestle_fedramp/core/baselines_test.py @@ -0,0 +1,36 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Testing populating the FedRAMP SSP Appendix A template.""" + +import pathlib + +import pytest + +from trestle_fedramp.core.baselines import BaselineLevel + + +def test_invalid_baseline_level() -> None: + """Test invalid baseline level.""" + with pytest.raises(ValueError, match='Invalid level: invalid. Use one of .*'): + BaselineLevel.get_template('invalid') + + +def test_valid_baseline_level() -> None: + """Test valid baseline levels and check that the template exists.""" + for level in BaselineLevel.LEVELS: + template = BaselineLevel.get_template(level) + assert template != '' + assert pathlib.Path(template).exists() diff --git a/tests/trestle_fedramp/core/docx_helper_test.py b/tests/trestle_fedramp/core/docx_helper_test.py new file mode 100644 index 0000000..3c0ed6a --- /dev/null +++ b/tests/trestle_fedramp/core/docx_helper_test.py @@ -0,0 +1,108 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright (c) 2021 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Testing docx utility classes.""" + +from docx.document import Document as DocxDocument # type: ignore + +import pytest + +from tests.test_utils import ( + verify_control_origination_checkboxes, + verify_implementation_status_checkboxes, + verify_parameters, + verify_responses, + verify_responsible_roles +) + +from trestle.common.err import TrestleError + +from trestle_fedramp import const +from trestle_fedramp.core.docx_helper import ControlImplementationDescriptions, ControlSummaries, FedrampDocx +from trestle_fedramp.core.ssp_reader import FedrampControlDict, FedrampSSPData + + +def test_fedramp_docx_populate(docx_document: DocxDocument, test_ssp_control_dict: FedrampControlDict) -> None: + """Test FedRAMP docx populate and verify the correct controls are populated.""" + fedramp_docx = FedrampDocx(docx_document, test_ssp_control_dict) + fedramp_docx.populate() + + # Read the table information validate the proper check boxes are populated + control_summaries = ControlSummaries() + control_implementation_description = ControlImplementationDescriptions() + for table in docx_document.tables: + row_header = table.rows[0].cells[0].text + if control_summaries.is_control_summary_table(row_header): + control_id = fedramp_docx.get_control_id(row_header) + data: FedrampSSPData = test_ssp_control_dict.get(control_id, FedrampSSPData({}, {}, None, None, None)) + verify_control_origination_checkboxes(table.cell(*control_summaries._control_origination_cell), data) + verify_implementation_status_checkboxes(table.cell(*control_summaries._implementation_status_cell), data) + # Check that the parameters are in the cell text (partial match) + verify_parameters(table, data.parameters, partial_match=True) + verify_responsible_roles(table.cell(*control_summaries._responsible_role_cell), data) + if control_implementation_description.is_control_implementation_table(row_header): + control_id = fedramp_docx.get_control_id(row_header) + data = test_ssp_control_dict.get(control_id, FedrampSSPData({}, {}, None, None, None)) + # Check that the responses are in the cell text (partial match) + verify_responses(table, data.control_implementation_description, partial_match=True) + + +def test_fedramp_docx_with_invalid_input(docx_document: DocxDocument) -> None: + """Trigger and error with invalid input.""" + # AC-1 does not have an control origination inherited value + invalid_control_dict: FedrampControlDict = { + 'AC-1': FedrampSSPData( + control_implementation_description={}, + parameters={}, + control_origination=[const.FEDRAMP_INHERITED], + implementation_status=None, + responsible_roles=None + ) + } + fedramp_docx = FedrampDocx(docx_document, invalid_control_dict) + + with pytest.raises(TrestleError, match='.*Invalid control origination: Inherited'): + fedramp_docx.populate() + + +def test_fedramp_docx_with_non_existent_values(docx_document: DocxDocument) -> None: + """Trigger and error with a non-existent control origination and implementation status.""" + # AC-1 does not have an control origination inherited value + invalid_control_dict: FedrampControlDict = { + 'AC-1': FedrampSSPData( + control_implementation_description={}, + parameters={}, + control_origination=['invalid'], + implementation_status=None, + responsible_roles=None + ) + } + fedramp_docx = FedrampDocx(docx_document, invalid_control_dict) + + with pytest.raises(TrestleError, match='.*Invalid FedRAMP control origination value: invalid'): + fedramp_docx.populate() + + invalid_control_dict['AC-1'].control_origination = [const.FEDRAMP_SP_CORPORATE] # Reset the control origination + invalid_control_dict['AC-1'].implementation_status = 'invalid' + + with pytest.raises(TrestleError, match='.*Invalid FedRAMP implementation status value: invalid'): + fedramp_docx.populate() + + +def test_get_control_id() -> None: + """Test FedRAMP docx get control id.""" + test_row_header = 'AC-2 Control Summary Information' + control_label = FedrampDocx.get_control_id(test_row_header) + assert control_label == 'AC-2' diff --git a/tests/trestle_fedramp/core/fedramp_values_test.py b/tests/trestle_fedramp/core/fedramp_values_test.py new file mode 100644 index 0000000..8c12f01 --- /dev/null +++ b/tests/trestle_fedramp/core/fedramp_values_test.py @@ -0,0 +1,74 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Tests for FedRAMP values translation.""" + +from typing import List + +import pytest + +from trestle_fedramp.const import ( + FEDRAMP_CUST_CONFIGURED, + FEDRAMP_HYBRID, + FEDRAMP_INHERITED, + FEDRAMP_SHARED, + FEDRAMP_SHORT_CUST_CONFIGURED, + FEDRAMP_SHORT_INHERITED, + FEDRAMP_SHORT_SP_CORPORATE, + FEDRAMP_SHORT_SP_SYSTEM, + FEDRAMP_SP_CORPORATE +) +from trestle_fedramp.core.fedramp_values import ControlOrigination + + +def test_control_origination() -> None: + """Test valid and invalid control origination values.""" + # Validate combinations of control origination values. + long_names: List[str] = ControlOrigination.get_long_names([FEDRAMP_SHORT_SP_CORPORATE, FEDRAMP_SHORT_SP_SYSTEM]) + assert long_names == [FEDRAMP_HYBRID] + + # Shared should take precedence over the other values. + long_names = ControlOrigination.get_long_names( + [FEDRAMP_SHORT_SP_CORPORATE, FEDRAMP_SHORT_SP_SYSTEM, FEDRAMP_SHORT_CUST_CONFIGURED] + ) + assert long_names == [FEDRAMP_SHARED] + + # Combination with inherited + long_names = ControlOrigination.get_long_names( + [FEDRAMP_SHORT_SP_CORPORATE, FEDRAMP_SHORT_CUST_CONFIGURED, FEDRAMP_SHORT_INHERITED] + ) + + assert len(long_names) == 2 + assert FEDRAMP_SHARED in long_names + assert FEDRAMP_INHERITED in long_names + + # Neither shared nor hybrid + long_names = ControlOrigination.get_long_names([FEDRAMP_SHORT_INHERITED, FEDRAMP_SHORT_CUST_CONFIGURED]) + + assert len(long_names) == 2 + assert FEDRAMP_INHERITED in long_names + assert FEDRAMP_CUST_CONFIGURED in long_names + + # Single value + long_names = ControlOrigination.get_long_names([FEDRAMP_SHORT_SP_CORPORATE]) + assert long_names == [FEDRAMP_SP_CORPORATE] + + # Assert that if the input is not a valid control origination value, it raises a ValueError. + with pytest.raises(ValueError, match='Invalid control origination value: invalid. Use one of .*'): + ControlOrigination.get_long_names([FEDRAMP_SHORT_CUST_CONFIGURED, 'invalid']) + + # Validate error for empty list. + with pytest.raises(ValueError, match='Control origination values are empty'): + ControlOrigination.get_long_names([]) diff --git a/tests/trestle_fedramp/core/ssp_reader_test.py b/tests/trestle_fedramp/core/ssp_reader_test.py new file mode 100644 index 0000000..741508c --- /dev/null +++ b/tests/trestle_fedramp/core/ssp_reader_test.py @@ -0,0 +1,171 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Testing reading OSCAL SSP data for FedRAMP transformation.""" + +import pathlib +from typing import Dict, Tuple + +import pytest + +from trestle.common.const import NAMESPACE_FEDRAMP +from trestle.common.model_utils import ModelUtils +from trestle.core.generators import generate_sample_model +from trestle.oscal import ssp +from trestle.oscal.common import Property, ResponsibleRole + +from trestle_fedramp.core.ssp_reader import FedrampControlDict, FedrampSSPReader + + +def test_reader_ssp_data(tmp_trestle_dir_with_ssp: Tuple[pathlib.Path, str]) -> None: + """Test retrieving information from an OSCAL SSP for FedRAMP.""" + tmp_trestle_dir, ssp_name = tmp_trestle_dir_with_ssp + ssp_file_path = ModelUtils.get_model_path_for_name_and_class(tmp_trestle_dir, ssp_name, ssp.SystemSecurityPlan) + assert ssp_file_path is not None + + ssp_reader: FedrampSSPReader = FedrampSSPReader(tmp_trestle_dir, ssp_file_path) + + ssp_control_dict: FedrampControlDict = ssp_reader.read_ssp_data() + assert len(ssp_control_dict) > 0 + + # Verify the control origination values for the implemented requirements. + assert ssp_control_dict['AC-1'].control_origination == ['Service Provider System Specific'] + assert ssp_control_dict['AC-2'].control_origination == ['Shared (Service Provider and Customer Responsibility)'] + assert ssp_control_dict['AU-1'].control_origination == ['Service Provider Corporate'] + + # Verify status + assert ssp_control_dict['AC-1'].implementation_status == 'Planned' + assert ssp_control_dict['AC-2'].implementation_status == 'Implemented' + assert ssp_control_dict['AU-1'].implementation_status == 'Partially Implemented' + + # Verify the control implementation descriptions + responses_dict: Dict[str, str] = ssp_control_dict['AC-1'].control_implementation_description + assert len(responses_dict) == 2 + assert '' not in responses_dict + assert 'a' in responses_dict + assert 'b' in responses_dict + + assert responses_dict['a'] == ( + 'This System: Describe how Part a is satisfied within the system.\n' + '\n[EXAMPLE]Policies: Describe how this policy component satisfies part a.' + ) + + assert responses_dict['b'] == ( + 'This System: Describe how Part b is satisfied within the system for a component.\n' + '\n[EXAMPLE]Procedures: Describe how Part b is satisfied within the system for ' + 'another component.' + ) + + # Verify the parameter values and overrides for an example control + param_dict = ssp_control_dict['AU-1'].parameters + assert len(param_dict) == 7 + assert 'AU-1(a)' in param_dict + assert 'AU-1(a)(1)' in param_dict + assert 'AU-1(b)' in param_dict + assert 'AU-1(c)(1)-1' in param_dict + assert 'AU-1(c)(1)-2' in param_dict + assert 'AU-1(c)(1)-1' in param_dict + assert 'AU-1(c)(2)-2' in param_dict + + assert param_dict['AU-1(a)'] == 'organization-defined personnel or roles' + assert param_dict['AU-1(a)(1)'] == '' + assert param_dict['AU-1(b)'] == '' + assert param_dict['AU-1(c)(1)-1'] == 'at least every 3 years' + assert param_dict['AU-1(c)(1)-2'] == '' + assert param_dict['AU-1(c)(2)-1'] == 'at least annually' + assert param_dict['AU-1(c)(2)-2'] == '' + + # Verify the responsible roles + assert ssp_control_dict['AC-2'].responsible_roles == [ + '[SAMPLE]Unix Administrator', 'System Information System Security Officer (or Equivalent)' + ] + + +def test_get_control_origination() -> None: + """Test getting control origination from the implemented requirement.""" + impl_req = generate_sample_model(ssp.ImplementedRequirement) + impl_req.props = [] + impl_req.props.append( + Property(name='control-origination', value='sp-corporate', ns='https://example.com') # type: ignore + ) + + # This should be none because the namespace is not the FedRAMP namespace. + assert FedrampSSPReader.get_control_origination_values(impl_req) is None + + impl_req.props = [] + impl_req.props.append( + Property(name='control-origination', value='sp-corporate', ns=NAMESPACE_FEDRAMP) # type: ignore + ) + + # This should return the long name of the control origination value. + assert FedrampSSPReader.get_control_origination_values(impl_req) == ['Service Provider Corporate'] + + +# Negative test cases for implementation status + + +def test_get_implementation_status_failures() -> None: + """Testing failure cases for getting the implementation status.""" + # Wrong namespace + impl_req = generate_sample_model(ssp.ImplementedRequirement) + impl_req.props = [] + impl_req.props.append( + Property(name='implementation-status', value='planned', ns='https://example.com') # type: ignore + ) + + assert FedrampSSPReader.get_implementation_status(impl_req) is None + + # Too many implementation status properties + impl_req.props = [] + impl_req.props.extend( + [ + Property(name='implementation-status', value='planned', ns=NAMESPACE_FEDRAMP), # type: ignore + Property(name='implementation-status', value='implemented', ns=NAMESPACE_FEDRAMP) # type: ignore + ] + ) + impl_req.control_id = 'ac-1' + + with pytest.raises(ValueError, match='Multiple implementation status properties found for control id .*'): + FedrampSSPReader.get_implementation_status(impl_req) + + # Invalid implementation status value + impl_req.props = [] + impl_req.props.append( + Property(name='implementation-status', value='invalid', ns=NAMESPACE_FEDRAMP) # type: ignore + ) + + with pytest.raises(ValueError, match='Invalid implementation status value: invalid. Use one of .*'): + FedrampSSPReader.get_implementation_status(impl_req) + + +# Negative test cases for responsible roles + + +def test_responsible_role_failures(tmp_trestle_dir_with_ssp: Tuple[pathlib.Path, str]) -> None: + """Testing failure cases for getting the responsible roles.""" + tmp_trestle_dir, ssp_name = tmp_trestle_dir_with_ssp + ssp_file_path = ModelUtils.get_model_path_for_name_and_class(tmp_trestle_dir, ssp_name, ssp.SystemSecurityPlan) + assert ssp_file_path is not None + + ssp_reader: FedrampSSPReader = FedrampSSPReader(tmp_trestle_dir, ssp_file_path) + # Wrong namespace + impl_req = generate_sample_model(ssp.ImplementedRequirement) + impl_req.control_id = 'ac-1' + responsible_role = generate_sample_model(ResponsibleRole) + responsible_role.role_id = 'invalid_role' + impl_req.responsible_roles = [responsible_role] + + with pytest.raises(ValueError, match='Role with id invalid_role for control ac-1 not found.*'): + ssp_reader.get_responsible_roles(impl_req) diff --git a/trestle_fedramp/commands/transform.py b/trestle_fedramp/commands/transform.py new file mode 100644 index 0000000..029ad40 --- /dev/null +++ b/trestle_fedramp/commands/transform.py @@ -0,0 +1,94 @@ +# -*- mode:python; coding:utf-8 -*- + +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Trestle FedRAMP Transform Command.""" + +import argparse +import logging +import pathlib + +from docx import Document # type: ignore +from docx.document import Document as DocxDocument # type: ignore + +import trestle.common.log as log +from trestle.common.err import TrestleError, handle_generic_command_exception +from trestle.common.model_utils import ModelUtils +from trestle.core.commands.command_docs import CommandPlusDocs +from trestle.core.commands.common import return_codes +from trestle.oscal import ssp + +from trestle_fedramp.core.baselines import BaselineLevel +from trestle_fedramp.core.docx_helper import FedrampDocx +from trestle_fedramp.core.ssp_reader import FedrampControlDict, FedrampSSPReader + +logger = logging.getLogger(__name__) + + +class SSPTransformCmd(CommandPlusDocs): + """Transform an OSCAL SSP to FedRAMP SSP Appendix A document.""" + + name = 'fedramp-transform' + + def _init_arguments(self) -> None: + logger.debug('Init arguments') + self.add_argument('-n', '--ssp-name', help='OSCAL SSP name from trestle workspace.', type=str, required=True) + self.add_argument( + '-l', + '--level', + required=True, + type=str, + choices=BaselineLevel.LEVELS, + help='FedRAMP Baseline level for template selection.', + ) + self.add_argument( + '-o', '--output-file', help='Output file for populated SSP Appendix A template', type=str, required=True + ) + + def _run(self, args: argparse.Namespace) -> int: + logger.debug('Entering trestle fedramp-transform.') + + log.set_log_level_from_args(args) + + ssp_file_path = ModelUtils.get_model_path_for_name_and_class( + args.trestle_root, args.ssp_name, ssp.SystemSecurityPlan + ) + + if ssp_file_path is None or not ssp_file_path.exists(): + logger.error(f'Input ssp {args.ssp_name} does not exist in the trestle workspace.') + return return_codes.CmdReturnCodes.COMMAND_ERROR.value + + try: + # If this error is thrown, there is a bug in the code + template = pathlib.Path(BaselineLevel.get_template(args.level)).resolve() + if not template.exists(): + raise TrestleError(f'Bug FedRAMP Template {template} does not exist') + + # Read the OSCAL SSP data + ssp_reader = FedrampSSPReader(args.trestle_root, ssp_file_path) + control_dict: FedrampControlDict = ssp_reader.read_ssp_data() + + # Load the document and save it for altering + with open(template, 'rb') as file: + document: DocxDocument = Document(file) + + # Populate the document with the OSCAL SSP data + fedramp_docx: FedrampDocx = FedrampDocx(document, control_dict) + fedramp_docx.populate() + + document.save(args.output_file) + except Exception as e: + return handle_generic_command_exception(e, logger) + + return return_codes.CmdReturnCodes.SUCCESS.value diff --git a/trestle_fedramp/const.py b/trestle_fedramp/const.py index d584718..6744134 100644 --- a/trestle_fedramp/const.py +++ b/trestle_fedramp/const.py @@ -15,6 +15,8 @@ # limitations under the License. """Core constants module containing all constants.""" +from typing import Dict, List + # FedRAMP related files and directories FEDRAM_BASELINE = 'fedramp-source/content/baselines/rev5/xml' FEDRAMP_REGISTRY = 'fedramp-source/content/resources/xml' @@ -25,3 +27,72 @@ NIST_SSP_JSON_XML_XSL = 'nist-source/xml/convert/oscal_ssp_json-to-xml-converter-new.xsl' NIST_INITIAL_TEMPLATE = 'from-json' NIST_FILE_PARAM_NAME = 'file' + +# FedRAMP related files for SSP Appendix A conversion +FEDRAMP_APPENDIX_A_LOW = 'fedramp-source/content/templates/SSP-Appendix-A-Low-FedRAMP-Security-Controls.docx' +FEDRAMP_APPENDIX_A_MODERATE = 'fedramp-source/content/templates/SSP-Appendix-A-Moderate-FedRAMP-Security-Controls.docx' +FEDRAMP_APPENDIX_A_HIGH = 'fedramp-source/content/templates/SSP-Appendix-A-High-FedRAMP-Security-Controls.docx' + +# CONTROL ORIGINATION FEDRAMP + +FEDRAMP_SHORT_SP_CORPORATE = 'sp-corporate' +FEDRAMP_SHORT_SP_SYSTEM = 'sp-system' +FEDRAMP_SHORT_CUST_CONFIGURED = 'customer-configured' +FEDRAMP_SHORT_CUST_PROVIDED = 'customer-provided' +FEDRAMP_SHORT_INHERITED = 'inherited' + +FEDRAMP_CO_VALUES: List[str] = [ + FEDRAMP_SHORT_SP_CORPORATE, + FEDRAMP_SHORT_SP_SYSTEM, + FEDRAMP_SHORT_CUST_CONFIGURED, + FEDRAMP_SHORT_CUST_PROVIDED, + FEDRAMP_SHORT_INHERITED +] + +FEDRAMP_SP_CORPORATE = 'Service Provider Corporate' +FEDRAMP_SP_SYSTEM = 'Service Provider System Specific' +FEDRAMP_CUST_CONFIGURED = 'Configured by Customer (Customer System Specific)' +FEDRAMP_CUST_PROVIDED = 'Provided by Customer (Customer System Specific)' +FEDRAMP_SHARED = 'Shared (Service Provider and Customer Responsibility)' +FEDRAMP_HYBRID = 'Service Provider Hybrid (Corporate and System Specific)' +FEDRAMP_INHERITED = 'Inherited' + +FEDRAMP_CO_SHORT_TO_LONG_NAME: Dict[str, str] = { + FEDRAMP_SHORT_SP_CORPORATE: FEDRAMP_SP_CORPORATE, + FEDRAMP_SHORT_SP_SYSTEM: FEDRAMP_SP_SYSTEM, + FEDRAMP_SHORT_CUST_CONFIGURED: FEDRAMP_CUST_CONFIGURED, + FEDRAMP_SHORT_CUST_PROVIDED: FEDRAMP_CUST_PROVIDED, + FEDRAMP_SHORT_INHERITED: FEDRAMP_INHERITED +} + +# FedRAMP Template Constants +CONTROL_SUMMARY = 'Control Summary Information' +CONTROL_RESPONSE = 'What is the solution and how is it implemented?' +XML_NAMESPACE = '{http://schemas.microsoft.com/office/word/2010/wordml}' +CHECKBOX_XPATH = './/w:sdt//w:sdtPr//w14:checkbox' +BOX_ICON_XPATH = './/w:sdt//w:sdtContent//w:r//w:t' +CHECKED_BOX_ICON = '☒' +FEDRAMP_STATEMENT_PREFIX = 'Part' +FEDRAMP_PARAMETER_PREFIX = 'Parameter' + +# Implementation Status FedRAMP + +FEDRAMP_SHORT_IMPLEMENTED = 'implemented' +FEDRAMP_SHORT_PARTIAL = 'partial' +FEDRAMP_SHORT_PLANNED = 'planned' +FEDRAMP_SHORT_ALTERNATIVE = 'alternative' +FEDRAMP_SHORT_NOT_APPLICABLE = 'not-applicable' + +FEDRAMP_IMPLEMENTED = 'Implemented' +FEDRAMP_PARTIAL = 'Partially Implemented' +FEDRAMP_PLANNED = 'Planned' +FEDRAMP_ALTERNATIVE = 'Alternative Implementation' +FEDRAMP_NOT_APPLICABLE = 'Not Applicable' + +FEDRAMP_IS_SHORT_TO_LONG_NAME: Dict[str, str] = { + FEDRAMP_SHORT_IMPLEMENTED: FEDRAMP_IMPLEMENTED, + FEDRAMP_SHORT_PARTIAL: FEDRAMP_PARTIAL, + FEDRAMP_SHORT_PLANNED: FEDRAMP_PLANNED, + FEDRAMP_SHORT_ALTERNATIVE: FEDRAMP_ALTERNATIVE, + FEDRAMP_SHORT_NOT_APPLICABLE: FEDRAMP_NOT_APPLICABLE +} diff --git a/trestle_fedramp/core/baselines.py b/trestle_fedramp/core/baselines.py new file mode 100644 index 0000000..f9666b1 --- /dev/null +++ b/trestle_fedramp/core/baselines.py @@ -0,0 +1,48 @@ +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Information about Baselines and templates.""" + +from pkg_resources import resource_filename + +from trestle_fedramp.const import (FEDRAMP_APPENDIX_A_HIGH, FEDRAMP_APPENDIX_A_LOW, FEDRAMP_APPENDIX_A_MODERATE) + + +class BaselineLevel: + """Represents the baseline level for the FedRAMP SSP.""" + + LOW = 'low' + MODERATE = 'moderate' + HIGH = 'high' + + LEVELS = {LOW, MODERATE, HIGH} + + @classmethod + def get_template(cls, level: str) -> str: + """Get the template file for the given level. + + Args: + level (str): The baseline level ('low', 'moderate', 'high'). + + Returns: + str: The file path of the template. + """ + resources_path = 'trestle_fedramp.resources' + data = { + cls.LOW: resource_filename(resources_path, FEDRAMP_APPENDIX_A_LOW), + cls.MODERATE: resource_filename(resources_path, FEDRAMP_APPENDIX_A_MODERATE), + cls.HIGH: resource_filename(resources_path, FEDRAMP_APPENDIX_A_HIGH) + } + if level not in cls.LEVELS: + raise ValueError(f'Invalid level: {level}. Use one of {cls.LEVELS}') + return data[level] diff --git a/trestle_fedramp/core/docx_helper.py b/trestle_fedramp/core/docx_helper.py new file mode 100644 index 0000000..997dd79 --- /dev/null +++ b/trestle_fedramp/core/docx_helper.py @@ -0,0 +1,251 @@ +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Classes for populate FedRAMP Docx template.""" + +import logging +from typing import Dict, List, Optional, Tuple + +from docx.document import Document # type: ignore +from docx.table import Table, _Cell # type: ignore +from docx.text.paragraph import Paragraph # type: ignore + +from trestle.common.err import TrestleError + +import trestle_fedramp.const as const +from trestle_fedramp.core.ssp_reader import FedrampControlDict, FedrampSSPData + +logger = logging.getLogger(__name__) + + +class FedrampDocx(): + """Class for populating the FedRAMP template.""" + + def __init__(self, docx: Document, control_dict: FedrampControlDict) -> None: + """Initialize the FedrampDocx class.""" + self.docx = docx + self.control_dict = control_dict + + self.row_header_location: Tuple[int, int] = (0, 0) + + self.control_summaries = ControlSummaries() + self.control_implementation_descriptions = ControlImplementationDescriptions() + + def populate(self) -> None: + """Populate the FedRAMP template.""" + try: + for table in self.docx.tables: + row_header: str = table.cell(*self.row_header_location).text + if self.control_summaries.is_control_summary_table(row_header): + control_id = self.get_control_id(row_header) + ssp_data: Optional[FedrampSSPData] = self.get_control_data(control_id) + if ssp_data: + self.control_summaries.populate_table(table, control_id, ssp_data) + + elif self.control_implementation_descriptions.is_control_implementation_table(row_header): + control_id = self.get_control_id(row_header) + ssp_data = self.get_control_data(control_id) + if ssp_data: + self.control_implementation_descriptions.populate_table(table, control_id, ssp_data) + except Exception as e: + raise TrestleError(f'Error populating FedRAMP template: {e}') + + def get_control_data(self, control_id: str) -> Optional[FedrampSSPData]: + """Get the control data from the control_dict.""" + if control_id in self.control_dict: + logging.debug(f'Found the control info for {control_id}.') + ssp_data: FedrampSSPData = self.control_dict[control_id] + return ssp_data + else: + logging.debug(f'Control {control_id} not found in the SSP data.') + return None + + @staticmethod + def get_control_id(row_header: str) -> str: + """Get the control id from the table.""" + return row_header.split(' ')[0] + + +class ControlSummaries(): + """Populate the control summaries in the FedRAMP template.""" + + def __init__(self) -> None: + """Initialize the ControlSummaries class.""" + # Control origination is always the last row in the table + self._control_origination_cell: Tuple[int, int] = (-1, 0) + self._control_origination_index_values: Dict[str, int] = { + const.FEDRAMP_SP_CORPORATE: 1, + const.FEDRAMP_SP_SYSTEM: 2, + const.FEDRAMP_HYBRID: 3, + const.FEDRAMP_CUST_CONFIGURED: 4, + const.FEDRAMP_CUST_PROVIDED: 5, + const.FEDRAMP_SHARED: 6, + const.FEDRAMP_INHERITED: 7 + } + # Implementation status is always the second last row in the table + self._implementation_status_cell: Tuple[int, int] = (-2, 0) + self._implementation_status_index_values: Dict[str, int] = { + const.FEDRAMP_IMPLEMENTED: 1, + const.FEDRAMP_PARTIAL: 2, + const.FEDRAMP_PLANNED: 3, + const.FEDRAMP_ALTERNATIVE: 4, + const.FEDRAMP_NOT_APPLICABLE: 5 + } + self._parameter_start_row = 2 + self._responsible_role_cell: Tuple[int, int] = (1, 0) + + @staticmethod + def is_control_summary_table(row_header: str) -> bool: + """Check if the table is a control summary table.""" + return row_header.endswith(const.CONTROL_SUMMARY) + + def get_control_origination_index(self, control_origination: str) -> int: + """ + Get paragraph index in the control origination cell by control origination string. + + Args: + control_origination: The control origination string. + + Returns: + The paragraph index location in the control origination cell + in the control summary table. + """ + if control_origination not in self._control_origination_index_values: + raise TrestleError(f'Invalid FedRAMP control origination value: {control_origination}') + return self._control_origination_index_values[control_origination] + + def get_implementation_status_index(self, implementation_status: str) -> int: + """ + Get paragraph index in the implementation status cell by implementation status string. + + Args: + implementation_status: The implementation status string. + + Returns: + The paragraph index location in the implementation status cell + in the control summary table. + """ + if implementation_status not in self._implementation_status_index_values: + raise TrestleError(f'Invalid FedRAMP implementation status value: {implementation_status}') + return self._implementation_status_index_values[implementation_status] + + def _set_checkbox(self, paragraph: Paragraph) -> None: + """Check the checkbox in the paragraph.""" + # Find the checkbox element and set the checked attribute to 1 + check_box = paragraph._element.xpath(const.CHECKBOX_XPATH)[0] + if check_box is None: + raise TrestleError(f'Checkbox not found in the paragraph with text: {paragraph.text}') + checked = check_box.find(f'{const.XML_NAMESPACE}checked') + checked.attrib[f'{const.XML_NAMESPACE}val'] = '1' + self._set_checkbox_text(paragraph) + + def _set_checkbox_text(self, paragraph: Paragraph) -> None: + """Set the checkbox text.""" + checkbox_text = paragraph._element.xpath(const.BOX_ICON_XPATH)[0] + if checkbox_text is None: + raise TrestleError(f'Checkbox text not found in the paragraph with text: {paragraph.text}') + logger.debug(f'Checkbox text found in the paragraph with text: {paragraph.text}') + checkbox_text.text = const.CHECKED_BOX_ICON + + def _set_control_origination(self, control_origination_cell: _Cell, control_origination_values: List[str]) -> None: + """Set the control origination in the cell.""" + for control_origination in control_origination_values: + co_paragraph_index_loc = self.get_control_origination_index(control_origination) + # Control origination is always the last row in the table + if co_paragraph_index_loc > len(control_origination_cell.paragraphs): + raise TrestleError(f'Invalid control origination: {control_origination}') + co_paragraph: Paragraph = control_origination_cell.paragraphs[co_paragraph_index_loc] + self._set_checkbox(co_paragraph) + + def _set_implementation_status(self, implementation_status_cell: _Cell, implementation_status: str) -> None: + """Set the implementation status in the cell.""" + is_paragraph_index_loc = self.get_implementation_status_index(implementation_status) + is_paragraph: Paragraph = implementation_status_cell.paragraphs[is_paragraph_index_loc] + if is_paragraph_index_loc > len(implementation_status_cell.paragraphs): + raise TrestleError(f'Invalid implementation status: {implementation_status}') + self._set_checkbox(is_paragraph) + + def _set_parameter_values(self, table: Table, parameter_values: Dict[str, str]) -> None: + """ + Set the parameter values in the cell. + + Args: + parameter_cells: The list of parameter cells. + parameter_values: The parameter values. + + Notes: In the control summary table parameters start in the second row after responsible role and + continue for a non-standard number of rows until the implementation status is reached. All other values + of the control summary stable have a standard location and number of rows. + """ + for cell in table.columns[0].cells[self._parameter_start_row:]: + label = self.get_parameter_id(cell.text) + parameter_text = parameter_values.get(label, '') + if parameter_text: + cell.text = cell.text + ' ' + parameter_text + + @staticmethod + def get_parameter_id(row_text: str) -> str: + """Get the parameter id from the row text.""" + if row_text.startswith(const.FEDRAMP_PARAMETER_PREFIX): + return row_text.split(' ')[1].strip(':') + else: + return '' + + def populate_table(self, table: Table, control_id: str, ssp_data: FedrampSSPData) -> None: + """Populate the table with the SSP data.""" + try: + if ssp_data.control_origination: + control_origination_cell: _Cell = table.cell(*self._control_origination_cell) + self._set_control_origination(control_origination_cell, ssp_data.control_origination) + if ssp_data.implementation_status: + implementation_status_cell: _Cell = table.cell(*self._implementation_status_cell) + self._set_implementation_status(implementation_status_cell, ssp_data.implementation_status) + if ssp_data.parameters: + self._set_parameter_values(table, ssp_data.parameters) + if ssp_data.responsible_roles: + responsible_role_cell: _Cell = table.cell(*self._responsible_role_cell) + responsible_role_str = ', '.join(ssp_data.responsible_roles) + responsible_role_cell.text = f'{responsible_role_cell.text} {responsible_role_str}' + except Exception as e: + raise TrestleError(f'Error populating control summary for {control_id}: {e}') + + +class ControlImplementationDescriptions(): + """Populate the control implementation description in the FedRAMP template.""" + + @staticmethod + def is_control_implementation_table(row_header: str) -> bool: + """Check if the table is a control implementation table.""" + return row_header.endswith(const.CONTROL_RESPONSE) + + @staticmethod + def get_part_id(part_information: str) -> str: + """Get the part id from the table.""" + if part_information.startswith(const.FEDRAMP_STATEMENT_PREFIX): + return part_information.split(' ')[1].strip(':') + else: + return '' + + def populate_table(self, table: Table, control_id: str, ssp_data: FedrampSSPData) -> None: + """Populate the table with the SSP data.""" + if ssp_data.control_implementation_description: + try: + # After the row header for each control implementation + for cell in table.columns[0].cells[1:]: + label = self.get_part_id(cell.text) + if label in ssp_data.control_implementation_description: + description_text: str = ssp_data.control_implementation_description[label] + paragraph: Paragraph = cell.add_paragraph(description_text) + paragraph.add_run().add_break() + except TrestleError as e: + raise TrestleError(f'Error populating control implementation description for {control_id}: {e}') diff --git a/trestle_fedramp/core/fedramp_values.py b/trestle_fedramp/core/fedramp_values.py new file mode 100644 index 0000000..cd91eaa --- /dev/null +++ b/trestle_fedramp/core/fedramp_values.py @@ -0,0 +1,101 @@ +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Classes for translating OSCAL values FedRAMP values to document values.""" + +from typing import List, Set + +from trestle_fedramp.const import ( + FEDRAMP_CO_SHORT_TO_LONG_NAME, + FEDRAMP_CO_VALUES, + FEDRAMP_HYBRID, + FEDRAMP_SHARED, + FEDRAMP_SHORT_CUST_CONFIGURED, + FEDRAMP_SHORT_CUST_PROVIDED, + FEDRAMP_SHORT_INHERITED, + FEDRAMP_SHORT_SP_CORPORATE, + FEDRAMP_SHORT_SP_SYSTEM +) + + +class ControlOrigination: + """Represents the FedRAMP control origination mapping per FedRAMP validation rules.""" + + customer_sp: List[str] = [FEDRAMP_SHORT_CUST_CONFIGURED, FEDRAMP_SHORT_CUST_PROVIDED] + provider_sp: List[str] = [FEDRAMP_SHORT_SP_CORPORATE, FEDRAMP_SHORT_SP_SYSTEM] + + @classmethod + def get_long_names(cls, control_origination_values: List[str]) -> List[str]: + """ + Get the long name for control origination value(s). + + Args: + control_origination_values: List of control origination values. + + Returns: + Long names for the control origination value or combination of values. + + Notes: + The input values can be a single or set control origination properties values. + Any set with sp-corporate and sp-system is considered as hybrid and any set with customer + and specific system is considered as shared. + + """ + # Validate the input values + if not control_origination_values: + raise ValueError('Control origination values are empty') + + for value in control_origination_values: + if value not in FEDRAMP_CO_VALUES: + raise ValueError(f'Invalid control origination value: {value}. Use one of {FEDRAMP_CO_VALUES}') + + long_names: Set[str] = set() + + # Inherited can be combined with other values + if FEDRAMP_SHORT_INHERITED in control_origination_values: + fedramp_inherited_long = FEDRAMP_CO_SHORT_TO_LONG_NAME[FEDRAMP_SHORT_INHERITED] + long_names.add(fedramp_inherited_long) + + # If the values are in the provider and customer set, then it is shared + # This would encompass hybrid if both service provider values are present + # with customer values. + if cls.is_shared(control_origination_values): + long_names.add(FEDRAMP_SHARED) + elif cls._is_hybrid(control_origination_values): + long_names.add(FEDRAMP_HYBRID) + else: + # Add individual long names if they don't belong to shared or hybrid + for value in control_origination_values: + long_names.add(FEDRAMP_CO_SHORT_TO_LONG_NAME[value]) + + return list(long_names) + + @staticmethod + def _is_hybrid(control_origination_values: List[str]) -> bool: + """Check if the control origination values are hybrid.""" + return ( + FEDRAMP_SHORT_SP_CORPORATE in control_origination_values + and FEDRAMP_SHORT_SP_SYSTEM in control_origination_values + ) + + @classmethod + def is_shared(cls, control_origination_values: List[str]) -> bool: + """Check if the control origination values are shared.""" + control_origination_set: Set[str] = set(control_origination_values) + + # If the values contain both customer and provider values, then it is shared + if control_origination_set.intersection(cls.provider_sp) and control_origination_set.intersection( + cls.customer_sp): + return True + + return False diff --git a/trestle_fedramp/core/ssp_reader.py b/trestle_fedramp/core/ssp_reader.py new file mode 100644 index 0000000..b14af33 --- /dev/null +++ b/trestle_fedramp/core/ssp_reader.py @@ -0,0 +1,327 @@ +# Copyright (c) 2024 IBM Corp. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Read and prepare OSCAL SSP information for template. + +The OSCAL SSP is stored in the FedRAMPControlDict in a way that +would be expected by the FedRAMP Template without knowledge of the +template structure/format. +Control ID -> Labels +Control Origination Property -> Control Origination String Value(s) +Control Implementation Description -> Dictionary of response for each part +Control Parameters -> Dictionary of parameter values for each part and location in the prose to match the +expected FedRAMP values +Responsible Roles -> String of responsible roles for the control separated by commas +""" + +import logging +import pathlib +import re +from dataclasses import dataclass +from typing import Dict, List, Optional + +from trestle.common.common_types import TypeWithByComps +from trestle.common.const import CONTROL_ORIGINATION, IMPLEMENTATION_STATUS, NAMESPACE_FEDRAMP, STATEMENT +from trestle.common.err import TrestleError +from trestle.common.list_utils import as_filtered_list, as_list +from trestle.common.load_validate import load_validate_model_path +from trestle.core.catalog.catalog_interface import CatalogInterface +from trestle.core.control_interface import ControlInterface, ParameterRep +from trestle.core.profile_resolver import ProfileResolver +from trestle.oscal import common +from trestle.oscal.catalog import Catalog, Control +from trestle.oscal.ssp import ImplementedRequirement, SetParameter, SystemSecurityPlan + +from trestle_fedramp.const import FEDRAMP_IS_SHORT_TO_LONG_NAME +from trestle_fedramp.core.fedramp_values import ControlOrigination + +logger = logging.getLogger(__name__) + + +@dataclass +class FedrampSSPData: + """ + Class to hold the OSCAL SSP data for FedRAMP SSP conversion. + + Fields: + control_implementation_description: Dictionary of control implementation description by control part + parameters: Dictionary of parameters by control part and prose placement in the SSP (e.g AC(1)(a)) + control_origination: Top level control origination values list + implementation_status: Implementation status value + + Notes: To conform to the convention used by Trestle to denote information at + the control level, will be '' in the control_implementation_description and parameters dictionaries. + """ + + control_implementation_description: Dict[str, str] + parameters: Dict[str, str] + control_origination: Optional[List[str]] + implementation_status: Optional[str] + responsible_roles: Optional[List[str]] + + +# FedRAMP data by control label +FedrampControlDict = Dict[str, FedrampSSPData] + + +class FedrampSSPReader: + """ + Read OSCAL SSP information for FedRAMP SSP conversion. + + Notes: This class provided an opinionated way to read the OSCAL SSP and + prepare the data for the FedRAMP Template. + """ + + def __init__( + self, + trestle_root: pathlib.Path, + ssp_path: pathlib.Path, + ) -> None: + """ + Initialize FedRAMP SSP reader. + + Args: + trestle_root: Trestle project root path. + ssp_path: Path to the OSCAL SSP. + """ + self._root = trestle_root + self._ssp: SystemSecurityPlan = load_validate_model_path(self._root, ssp_path) # type: ignore + + resolved_catalog: Catalog = ProfileResolver.get_resolved_profile_catalog( + self._root, + self._ssp.import_profile.href, + param_rep=ParameterRep.LEAVE_MOUSTACHE, + ) + self.catalog_interface = CatalogInterface(resolved_catalog) + + # Setup dictionaries for control and statement mapping + self._control_labels_by_id: Dict[str, str] = self._load_label_info() + self._statement_labels_by_id: Dict[str, Dict[str, + str]] = self.catalog_interface.get_statement_part_id_map(False) + + # Setup dictionaries for component title. Only include components that are in the include_components list. + self._comp_titles_by_uuid: Dict[str, str] = self._get_component_info() + + self._roles_by_id: Dict[str, str] = self._get_roles() + + def _get_component_info(self) -> Dict[str, str]: + """Get the component information mapped to UUID.""" + return {component.uuid: component.title for component in as_list(self._ssp.system_implementation.components)} + + def _load_label_info(self) -> Dict[str, str]: + """Load the profile and store the control by label.""" + controls_by_label: Dict[str, str] = {} + + for control in self.catalog_interface.get_all_controls_from_dict(): + label = ControlInterface.get_label(control) + if label: + controls_by_label[control.id] = label + return controls_by_label + + def _get_roles(self) -> Dict[str, str]: + """Get the roles by ID.""" + return {role.id: role.title for role in as_list(self._ssp.metadata.roles)} + + def read_ssp_data(self) -> FedrampControlDict: + """Read the ssp from file and return the data for the FedRAMP Template.""" + control_dict: FedrampControlDict = {} + + for implemented_requirement in as_list(self._ssp.control_implementation.implemented_requirements): + control_id = implemented_requirement.control_id + label = self._control_labels_by_id.get(control_id, None) + if label: + control_origination: Optional[List[str]] = self.get_control_origination_values(implemented_requirement) + control_implementation_description: Dict[ + str, str] = self.get_control_implementation_description(implemented_requirement) + implementation_status: Optional[str] = self.get_implementation_status(implemented_requirement) + parameters: Dict[str, str] = self.get_control_parameters(implemented_requirement) + responsible_roles: Optional[List[str]] = self.get_responsible_roles(implemented_requirement) + control_dict[label] = FedrampSSPData( + control_origination=control_origination, + control_implementation_description=control_implementation_description, + implementation_status=implementation_status, + parameters=parameters, + responsible_roles=responsible_roles + ) + return control_dict + + def get_control_implementation_description(self, implemented_requirement: ImplementedRequirement) -> Dict[str, str]: + """Get the control implementation description.""" + control_implementation_description: Dict[str, str] = {} + + response_text: str = self._get_responses_from_by_comp(implemented_requirement) + if response_text: + control_implementation_description[''] = response_text + + statement_labels = self._statement_labels_by_id.get(implemented_requirement.control_id, {}) + + for statement in as_list(implemented_requirement.statements): + statement_label = statement_labels.get(statement.statement_id, '') + # Remove ending period from statement label to ensure consistency + statement_label = statement_label[:-1] if statement_label and statement_label.endswith( + '.' + ) else statement_label + if statement_label: + response_text = self._get_responses_from_by_comp(statement) + if response_text: + control_implementation_description[statement_label] = response_text + + return control_implementation_description + + def _get_responses_from_by_comp(self, type_with_bycomp: TypeWithByComps) -> str: + """Get the control implementation description for each by component.""" + control_response_text_list: List[str] = [ # type: ignore + f"{self._comp_titles_by_uuid.get(by_component.component_uuid, '')}: {by_component.description}" + for by_component in as_list(type_with_bycomp.by_components) # type: ignore + if by_component.description + ] + return '\n\n'.join(control_response_text_list) + + def get_control_parameters(self, implemented_requirement: ImplementedRequirement) -> Dict[str, str]: + """Get the control parameters.""" + parameters: Dict[str, str] = {} + control: Optional[Control] = self.catalog_interface.get_control(implemented_requirement.control_id) + if control is None: + raise TrestleError(f'Control {implemented_requirement.control_id} not found in the catalog') + + control_parameters = ControlInterface.get_control_param_dict(control, False) + # Replace all of the parameter with the resolved values from the catalog, profile, or set parameters + for param_id, param in control_parameters.items(): + logger.debug(f'Using parameter key {param_id} for control {implemented_requirement.control_id}') + # Set parameters can be set at the by_comp level, but only supporting at the control level + # for now since that is used in compliance-trestle during + # SSP markdown editing. + if implemented_requirement.set_parameters: + self._update_param(param, implemented_requirement.set_parameters) + param_str = ControlInterface.param_to_str(param, ParameterRep.VALUE_OR_EMPTY_STRING) + parameters[param_id] = param_str if param_str else '' + + parameters_by_part_name: Dict[str, str] = {} + label = self._control_labels_by_id.get(implemented_requirement.control_id, '') + for part in as_filtered_list(control.parts, lambda p: p.name == STATEMENT): + self._get_parameters_by_part(part, label, parameters, parameters_by_part_name) + return parameters_by_part_name + + def _update_param(self, parameter: common.Parameter, set_params: List[SetParameter]) -> None: + """Update the parameter value from the implemented requirement.""" + for set_param in as_filtered_list(set_params, lambda p: p.param_id == parameter.id): + if set_param.values: + logger.debug(f'Updating parameter {parameter.id} with values {set_param.values}') + parameter.values = set_param.values + return + + def _get_parameters_by_part( + self, part: common.Part, label: str, parameters: Dict[str, str], parameters_by_part_name: Dict[str, str] + ) -> None: + """ + Get the control parameters for a specific part. + + Notes: + Map them to the control part and prose location in the way that is expected by the FedRAMP template + The pattern is 'control(part)(subpart) or 'control(part)'. If there are multiple associated parameters + they are separated list in order with a dash in the key (e.g. AT-3(b)-1). + """ + part_label = ControlInterface.get_label(part) + part_label = part_label[:-1] if part_label and part_label.endswith('.') else part_label + if part_label: + label = f'{label}({part_label})' + if part.prose: + params_ids = self.find_params_in_text(part.prose) + if len(params_ids) == 1: + parameters_by_part_name[label] = parameters.get(params_ids[0], '') + elif params_ids: + for i, param_id in enumerate(params_ids): + parameters_by_part_name[f'{label}-{i+1}'] = parameters.get(param_id, '') + for subpart in as_list(part.parts): + self._get_parameters_by_part(subpart, label, parameters, parameters_by_part_name) + + def find_params_in_text(self, text: str) -> List[str]: + """Find the parameters in the text.""" + # Logic adapted from + # https://github.com/oscal-compass/compliance-trestle/blob/main/trestle/core/control_interface.py#L836 + param_ids: List[str] = [] + staches: List[str] = re.findall(r'{{.*?}}', text) + if not staches: + return param_ids + # now have list of all staches including braces, e.g. ['{{foo}}', '{{bar}}'] + # clean the staches so they just have the param ids + for stache in staches: + # remove braces so these are just param_ids but may have extra chars + stache_contents = stache[2:(-2)] + param_id = stache_contents.replace('insert: param,', '').strip() + param_ids.append(param_id) + return param_ids + + def get_responsible_roles(self, implemented_requirement: ImplementedRequirement) -> Optional[List[str]]: + """Get the responsible roles.""" + responsible_roles: List[str] = [] + for role in as_list(implemented_requirement.responsible_roles): + role_title = self._roles_by_id.get(role.role_id, '') + if role_title: + responsible_roles.append(role_title) + else: + raise ValueError( + f'Role with id {role.role_id} for control ' + f'{implemented_requirement.control_id} not found in the metadata roles' + ) + if not responsible_roles: + return None + return responsible_roles + + @staticmethod + def get_implementation_status(implemented_requirement: ImplementedRequirement) -> Optional[str]: + """Get the implementation status.""" + prop_values: List[str] = [ + prop.value + for prop in as_list(implemented_requirement.props) + if prop.name == IMPLEMENTATION_STATUS and prop.ns == NAMESPACE_FEDRAMP + ] + + if not prop_values: + return None + elif len(prop_values) > 1: + raise ValueError( + 'Multiple implementation status properties found for control id ' + f'{implemented_requirement.control_id} implemented requirement' + ) + + implementation_status_value = prop_values[0] + + if implementation_status_value not in FEDRAMP_IS_SHORT_TO_LONG_NAME: + raise ValueError( + f'Invalid implementation status value: {implementation_status_value}. ' + f'Use one of {list(FEDRAMP_IS_SHORT_TO_LONG_NAME.keys())}' + ) + + return FEDRAMP_IS_SHORT_TO_LONG_NAME[implementation_status_value] + + @staticmethod + def get_control_origination_values(implemented_requirement: ImplementedRequirement) -> Optional[List[str]]: + """ + Check for the control origination property and return the value. + + Notes: + This is checking for the FedRAMP specific property in the OSCAL SSP, + not the OSCAL control origination values. + """ + prop_values: List[str] = [ + prop.value + for prop in as_list(implemented_requirement.props) + if prop.name == CONTROL_ORIGINATION and prop.ns == NAMESPACE_FEDRAMP + ] + + if not prop_values: + return None + + return ControlOrigination.get_long_names(prop_values) diff --git a/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-High-FedRAMP-Security-Controls.docx b/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-High-FedRAMP-Security-Controls.docx new file mode 100644 index 0000000..858296a Binary files /dev/null and b/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-High-FedRAMP-Security-Controls.docx differ diff --git a/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-Low-FedRAMP-Security-Controls.docx b/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-Low-FedRAMP-Security-Controls.docx new file mode 100644 index 0000000..6c11af9 Binary files /dev/null and b/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-Low-FedRAMP-Security-Controls.docx differ diff --git a/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-Moderate-FedRAMP-Security-Controls.docx b/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-Moderate-FedRAMP-Security-Controls.docx new file mode 100644 index 0000000..42b667a Binary files /dev/null and b/trestle_fedramp/resources/fedramp-source/content/templates/SSP-Appendix-A-Moderate-FedRAMP-Security-Controls.docx differ