diff --git a/docs/content/en/docs/installation-configuration/_index.md b/docs/content/en/docs/installation-configuration/_index.md index 2ccfe091e..fc789b1bd 100644 --- a/docs/content/en/docs/installation-configuration/_index.md +++ b/docs/content/en/docs/installation-configuration/_index.md @@ -67,3 +67,15 @@ More information on setting up authentication can be found [here](/docs/installa | COOKIE_SECRET_KEY | `SOME_COOKIE_SECRET` | Optional: Secret key for cookies. Generate using `openssl rand -base64 32` or `head -c 32 /dev/urandom | base64`. | | OIDC_SKIP_TLS_VERIFY | `true` | Set whether to skip TLS verification. Default is `true`. | | AUTH_GROUP | `soarca_admin` | Specify the group users must belong to for authentication against SOARCA. | + +----- + +#### Key management system +{{% alert title="Note" color="primary" %}} +More information on the key management system can be found [here](/docs/soarca-extensions/key-management-system). +{{% /alert %}} +| Variable | Content | Description | +|------------------------|---------------------------------------------|---------------------------------------------------------------------------------------------| +| ENABLE_SSH_KMS | `false` | Enable the key management system for SSH| +| SSH_KMS_DIR | `deployments/docker/testing/ssh-kms-test/ssh-keystore/`| Set the folder where SSH keys for the key management system are stored| + diff --git a/docs/content/en/docs/soarca-extensions/key-management-system.md b/docs/content/en/docs/soarca-extensions/key-management-system.md new file mode 100644 index 000000000..dc072e39f --- /dev/null +++ b/docs/content/en/docs/soarca-extensions/key-management-system.md @@ -0,0 +1,40 @@ +--- +title: Key management system +description: > + Organizing keys used in SSH connections +categories: [capabilities] +tags: [native] +weight: 2 +date: 2023-01-05 +--- + +This page details the key management system that is built into SOARCA. +It currently works only in conjunction with the [SSH capability](./native-capabilities/#SSH). + +## Activation + +The KMS feature of SOARCA is enabled by setting [environment variables](../installation-configuration/#key-management-system). + +## Use in SSH commands + +The KMS can be referenced inside a playbook inside a [user-auth](https://docs.oasis-open.org/cacao/security-playbooks/v2.0/cs01/security-playbooks-v2.0-cs01.html#_Toc152256508) element. +This element is referenced by the [ssh command](https://docs.oasis-open.org/cacao/security-playbooks/v2.0/cs01/security-playbooks-v2.0-cs01.html#_Toc152256500). +To use the KMS the value kms must be set to true, and the value kms_key_identifier must be set to the name of the key. + +The use of the KMS overrides a specified password. + +## Underlying structure + +The key management system relies on an underlying folder with public and private keys. +The name of the key referenced by the user in the kms_key_identifier field is the name of the private key file. +SOARCA caches the keys, and the API allows the user to refresh the system, which loads any potential new key files found in the underlying directory. +Adding a key through the API also creates new files for storing the keys. + +The system also allows the user to revoke keys through the API. +This moves the keys to a directory called .revoked inside the key storage, and appends the time and date of the revocation to the key name. +It is up to the user to actually delete these keys or to recover keys. + +## API + +The API endpoints for the KMS are documented [here](/docs/soarca-api/#key-management-system) + diff --git a/docs/static/openapi/swagger.json b/docs/static/openapi/swagger.json index ee7eee092..f14e4f60c 100644 --- a/docs/static/openapi/swagger.json +++ b/docs/static/openapi/swagger.json @@ -6,6 +6,256 @@ "version": "1.0.0" }, "paths": { + "/keymanagement/": { + "get": { + "description": "return all keys in the KMS", + "produces": [ + "application/json" + ], + "tags": [ + "keymanagement" + ], + "summary": "gets all keys from the KMS", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, + "/keymanagement/:keyname/": { + "put": { + "description": "adds a key to the KMS; load key into cache and write file", + "produces": [ + "application/json" + ], + "tags": [ + "keymanagement" + ], + "summary": "add key to KMS", + "parameters": [ + { + "description": "key", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.KeyManagementKey" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "json" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + }, + "delete": { + "description": "revokes the key by moving it to .revoked and renaming it", + "produces": [ + "application/json" + ], + "tags": [ + "keymanagement" + ], + "summary": "remove key from KMS", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "json" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, + "/keymanagement/refresh/": { + "post": { + "description": "refresh the KMS and re-parse the underlying directory", + "produces": [ + "application/json" + ], + "tags": [ + "keymanagement" + ], + "summary": "refresh the KMS system, which allows the user to include manually added files in the KMS", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "json" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, + "/manual/": { + "get": { + "description": "get all pending manual commands that still needs values to be returned", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manual" + ], + "summary": "get all pending manual commands that still needs values to be returned", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/api.InteractionCommandData" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/api.InteractionCommandData" + } + } + } + } + } + }, + "/manual/continue": { + "post": { + "description": "updates the value of a variable according to the manual interaction", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manual" + ], + "summary": "updates the value of a variable according to the manual interaction", + "parameters": [ + { + "type": "string", + "description": "execution ID", + "name": "exec_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "step ID", + "name": "step_id", + "in": "path", + "required": true + }, + { + "description": "playbook", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.ManualOutArgsUpdatePayload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.Execution" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, + "/manual/{exec_id}/{step_id}": { + "get": { + "description": "get a specific manual command that still needs a value to be returned", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "manual" + ], + "summary": "get a specific manual command that still needs a value to be returned", + "parameters": [ + { + "type": "string", + "description": "execution ID", + "name": "exec_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "step ID", + "name": "step_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.InteractionCommandData" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, "/playbook/": { "get": { "description": "return all stored playbooks default limit:100", @@ -460,6 +710,123 @@ } } }, + "api.InteractionCommandData": { + "type": "object", + "required": [ + "command", + "description", + "execution_id", + "out_args", + "playbook_id", + "step_id", + "target", + "type" + ], + "properties": { + "command": { + "description": "The command for the agent either command", + "type": "string" + }, + "commandb64": { + "description": "Indicates if the command is in b64", + "type": "boolean" + }, + "description": { + "description": "The description from the workflow step", + "type": "string" + }, + "execution_id": { + "description": "The id of the execution", + "type": "string" + }, + "out_args": { + "description": "Map of cacao variables handled in the step out args with current values and definitions", + "allOf": [ + { + "$ref": "#/definitions/cacao.Variables" + } + ] + }, + "playbook_id": { + "description": "The id of the CACAO playbook executed by the execution", + "type": "string" + }, + "step_id": { + "description": "The id of the step executed by the execution", + "type": "string" + }, + "target": { + "description": "Map of cacao agent-target with the target(s) of this command", + "allOf": [ + { + "$ref": "#/definitions/cacao.AgentTarget" + } + ] + }, + "type": { + "description": "The type of this content", + "type": "string", + "example": "execution-status" + } + } + }, + "api.KeyManagementKey": { + "type": "object", + "properties": { + "private": { + "type": "string" + }, + "public": { + "type": "string" + } + } + }, + "api.ManualOutArgsUpdatePayload": { + "type": "object", + "required": [ + "execution_id", + "playbook_id", + "response_out_args", + "response_status", + "step_id", + "type" + ], + "properties": { + "execution_id": { + "description": "The id of the execution", + "type": "string" + }, + "playbook_id": { + "description": "The id of the CACAO playbook executed by the execution", + "type": "string" + }, + "response_out_args": { + "description": "Map of cacao variables storing the out args value, handled in the step out args, with current values and definitions", + "allOf": [ + { + "$ref": "#/definitions/cacao.Variables" + } + ] + }, + "response_status": { + "description": "Indicates status of command", + "allOf": [ + { + "$ref": "#/definitions/manual.ManualResponseStatus" + } + ] + }, + "step_id": { + "description": "The id of the step executed by the execution", + "type": "string" + }, + "type": { + "description": "The type of this content", + "type": "string", + "example": "string" + } + } + }, "api.PlaybookExecutionReport": { "type": "object", "properties": { @@ -1307,6 +1674,7 @@ "type": "integer" }, "type": { + "description": "The uuid of the step (not part of CACAO spec, but included in object for utility)", "type": "string" } } @@ -1333,7 +1701,7 @@ "example": false }, "name": { - "description": "The name of the variable in the style __variable_name__", + "description": "The name of the variable in the style __variable_name__ (not part of CACAO spec, but included in object for utility)", "type": "string", "example": "__example_string__" }, @@ -1360,6 +1728,17 @@ "additionalProperties": { "$ref": "#/definitions/cacao.Step" } + }, + "manual.ManualResponseStatus": { + "type": "string", + "enum": [ + "success", + "failure" + ], + "x-enum-varnames": [ + "ManualResponseSuccessStatus", + "ManualResponseFailureStatus" + ] } } } \ No newline at end of file diff --git a/docs/static/openapi/swagger.yaml b/docs/static/openapi/swagger.yaml index 1e707e574..b590e4536 100644 --- a/docs/static/openapi/swagger.yaml +++ b/docs/static/openapi/swagger.yaml @@ -30,6 +30,88 @@ definitions: - execution_id - payload type: object + api.InteractionCommandData: + properties: + command: + description: The command for the agent either command + type: string + commandb64: + description: Indicates if the command is in b64 + type: boolean + description: + description: The description from the workflow step + type: string + execution_id: + description: The id of the execution + type: string + out_args: + allOf: + - $ref: '#/definitions/cacao.Variables' + description: Map of cacao variables handled in the step out args with current + values and definitions + playbook_id: + description: The id of the CACAO playbook executed by the execution + type: string + step_id: + description: The id of the step executed by the execution + type: string + target: + allOf: + - $ref: '#/definitions/cacao.AgentTarget' + description: Map of cacao agent-target with the target(s) of this command + type: + description: The type of this content + example: execution-status + type: string + required: + - command + - description + - execution_id + - out_args + - playbook_id + - step_id + - target + - type + type: object + api.KeyManagementKey: + properties: + private: + type: string + public: + type: string + type: object + api.ManualOutArgsUpdatePayload: + properties: + execution_id: + description: The id of the execution + type: string + playbook_id: + description: The id of the CACAO playbook executed by the execution + type: string + response_out_args: + allOf: + - $ref: '#/definitions/cacao.Variables' + description: Map of cacao variables storing the out args value, handled in + the step out args, with current values and definitions + response_status: + allOf: + - $ref: '#/definitions/manual.ManualResponseStatus' + description: Indicates status of command + step_id: + description: The id of the step executed by the execution + type: string + type: + description: The type of this content + example: string + type: string + required: + - execution_id + - playbook_id + - response_out_args + - response_status + - step_id + - type + type: object api.PlaybookExecutionReport: properties: description: @@ -598,6 +680,8 @@ definitions: timeout: type: integer type: + description: The uuid of the step (not part of CACAO spec, but included in + object for utility) type: string required: - type @@ -617,7 +701,8 @@ definitions: example: false type: boolean name: - description: The name of the variable in the style __variable_name__ + description: The name of the variable in the style __variable_name__ (not + part of CACAO spec, but included in object for utility) example: __example_string__ type: string type: @@ -639,11 +724,185 @@ definitions: additionalProperties: $ref: '#/definitions/cacao.Step' type: object + manual.ManualResponseStatus: + enum: + - success + - failure + type: string + x-enum-varnames: + - ManualResponseSuccessStatus + - ManualResponseFailureStatus info: contact: {} title: SOARCA API version: 1.0.0 paths: + /keymanagement/: + get: + description: return all keys in the KMS + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + type: string + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: gets all keys from the KMS + tags: + - keymanagement + /keymanagement/:keyname/: + delete: + description: revokes the key by moving it to .revoked and renaming it + produces: + - application/json + responses: + "200": + description: OK + schema: + type: json + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: remove key from KMS + tags: + - keymanagement + put: + description: adds a key to the KMS; load key into cache and write file + parameters: + - description: key + in: body + name: data + required: true + schema: + $ref: '#/definitions/api.KeyManagementKey' + produces: + - application/json + responses: + "200": + description: OK + schema: + type: json + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: add key to KMS + tags: + - keymanagement + /keymanagement/refresh/: + post: + description: refresh the KMS and re-parse the underlying directory + produces: + - application/json + responses: + "200": + description: OK + schema: + type: json + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: refresh the KMS system, which allows the user to include manually added + files in the KMS + tags: + - keymanagement + /manual/: + get: + consumes: + - application/json + description: get all pending manual commands that still needs values to be returned + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/api.InteractionCommandData' + type: array + "400": + description: Bad Request + schema: + items: + $ref: '#/definitions/api.InteractionCommandData' + type: array + summary: get all pending manual commands that still needs values to be returned + tags: + - manual + /manual/{exec_id}/{step_id}: + get: + consumes: + - application/json + description: get a specific manual command that still needs a value to be returned + parameters: + - description: execution ID + in: path + name: exec_id + required: true + type: string + - description: step ID + in: path + name: step_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.InteractionCommandData' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: get a specific manual command that still needs a value to be returned + tags: + - manual + /manual/continue: + post: + consumes: + - application/json + description: updates the value of a variable according to the manual interaction + parameters: + - description: execution ID + in: path + name: exec_id + required: true + type: string + - description: step ID + in: path + name: step_id + required: true + type: string + - description: playbook + in: body + name: data + required: true + schema: + $ref: '#/definitions/api.ManualOutArgsUpdatePayload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.Execution' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: updates the value of a variable according to the manual interaction + tags: + - manual /playbook/: get: description: return all stored playbooks default limit:100 diff --git a/makefile b/makefile index 6d3de330d..79c570382 100644 --- a/makefile +++ b/makefile @@ -9,9 +9,13 @@ GOLDFLAGS += -X main.Version=$(VERSION) GOLDFLAGS += -X main.Buildtime=$(BUILDTIME) GOFLAGS = -ldflags "$(GOLDFLAGS)" +# This creates the swagger.json and swagger.yaml files in api/. \ +# These can be copied to docs/static/openapi to provide convenient api documentation +# The same overview of the build can be viewed at /swagger/index.html, including for local build. swagger: mkdir -p api - swag init -g main.go -o api -d cmd/soarca/,api + swag init -o api -d cmd/soarca/,pkg/models/api,pkg/models/cacao,pkg/models/manual,pkg/api -g main.go + lint: swagger