Google Key Management Service
Use the Google Key Management Service API for CryptoKey management and encrypt/decrypt functionality.
Network Security · Google Key Management Service
Details
| ID | Google Key Management Service |
|---|---|
| Provider | |
| Category | Network Security |
| From Version | 5.0.0 |
| Docker Image | demisto/google-kms:1.0.0.10182333 |
| Supported Modules | Agentix XSIAM |
README
Use the Google Key Management Service API for CryptoKey management and encrypt/decrypt functionality.
Configure Google Key Management Service in Cortex
| Parameter | Required |
|---|---|
| User’s Service Account JSON | True |
| Project in Google Cloud KMS | True |
| Default Location | True |
| Default Key Ring | False |
| Use system proxy settings | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
google-kms-create-key
Creates a new CryptoKey within a KeyRing.
Base Command
google-kms-create-key
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the created crypto-key. It must be unique within a KeyRing and match the regular expression [a-zA-Z0-9_-]{1,63}. | Required |
| labels | Labels with user-defined metadata. | Optional |
| next_rotation_time | Date of the next scheduled rotation time. The Key Management Service automatically creates a new version of this CryptoKey and marks the new version as primary at the next rotation time. Key rotations performed manually through cryptoKeyVersions.create and cryptoKeys.updatePrimaryVersion do not affect nextRotationTime. Keys with purpose ENCRYPT_DECRYPT support automatic rotation. For other keys, this field must be omitted. A timestamp or a date in RFC3339 UTC “Zulu” format, accurate to nanoseconds. For example, “2014-10-02T15:01:23.045123456Z”. If left empty, it is set in 90 days. |
Optional |
| attestation | The statement that was generated and signed by the HSM at the key creation time. Use this statement to verify attributes of the key as stored on the HSM, independently of Google. Only provided for key versions with protectionLevel HSM. | Optional |
| state | The state of a CryptoKeyVersion, indicating if it can be used. Can be: “CRYPTO_KEY_VERSION_STATE_UNSPECIFIED, “PENDING_GENERATION”, “ENABLED”, “DISABLED”, “DESTROYED”, “DESTROY_SCHEDULED” , “PENDING_IMPORT”, “ IMPORT_FAILED”. Possible values are: CRYPTO_KEY_VERSION_STATE_UNSPECIFIED, PENDING_GENERATION, ENABLED, DISABLED, DESTROYED, DESTROY_SCHEDULED, PENDING_IMPORT, IMPORT_FAILED. Default is ENABLED. | Optional |
| purpose | The cryptographic capabilities of a CryptoKey. A given key can only be used for the operations allowed by its purpose. Can be: “CRYPTO_KEY_PURPOSE_UNSPECIFIED”, “ENCRYPT_DECRYPT”, “ASYMMETRIC_SIGN”, “ASYMMETRIC_DECRYPT”. Possible values are: CRYPTO_KEY_PURPOSE_UNSPECIFIED, ENCRYPT_DECRYPT, ASYMMETRIC_SIGN, ASYMMETRIC_DECRYPT. Default is ENCRYPT_DECRYPT. | Required |
| rotation_period | The time between when new key versions are generated automatically. Must be between 24 hours and 876,000 hours. Keys with ENCRYPT_DECRYPT purpose support automatic rotation. For other keys, this field must be omitted. A duration in seconds. Default is 7776000. | Required |
| algorithm | Algorithm to use when creating a CryptoKeyVersion based on this template. Possible values are: CRYPTO_KEY_VERSION_ALGORITHM_UNSPECIFIED, GOOGLE_SYMMETRIC_ENCRYPTION, RSA_SIGN_PSS_2048_SHA256, RSA_SIGN_PSS_3072_SHA256, RSA_SIGN_PSS_4096_SHA256, RSA_SIGN_PSS_4096_SHA512, RSA_SIGN_PKCS1_2048_SHA256, RSA_SIGN_PKCS1_3072_SHA256, RSA_SIGN_PKCS1_4096_SHA256, RSA_SIGN_PKCS1_4096_SHA512, RSA_DECRYPT_OAEP_2048_SHA256, RSA_DECRYPT_OAEP_3072_SHA256, RSA_DECRYPT_OAEP_4096_SHA256, RSA_DECRYPT_OAEP_4096_SHA512, EC_SIGN_P256_SHA256, EC_SIGN_P384_SHA384. Default is GOOGLE_SYMMETRIC_ENCRYPTION. | Optional |
| protection_level | Protections levels for cryptographic operations when creating a CryptoKeyVersion. Can be: Can be: “PROECTECTION_LEVEL_UNSPECIFIED”, “SOFTWARE”, “HSM”. Default is “SOFTWARE”. Possible values are: PROTECTION_LEVEL_UNSPECIFIED, SOFTWARE, HSM. Default is SOFTWARE. | Optional |
| skip_initial_version_creation | Whether to create a CryptoKey without any CryptoKeyVersions. You have to create the CryptoKeyVersion to use this key. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.CryptoKey.Name | String | The resource name for this CryptoKey. |
| GoogleKMS.CryptoKey.Purpose | String | The immutable purpose of this CryptoKey. |
| GoogleKMS.CryptoKey.CreationTime | String | The time when this CryptoKey was created. |
| GoogleKMS.CryptoKey.NextRotationTime | Date | The date when the next scheduled rotation is due to run. At nextRotationTime, the Key Management Service automatically |
| creates a new version of this CryptoKey and marks the new version as primary. | ||
| GoogleKMS.CryptoKey.RotationPeriod | String | The period for which the nextRotationTime is advanced, when the service automatically rotates a key. |
| GoogleKMS.CryptoKey.Labels | String | Labels with user-defined metadata. |
| GoogleKMS.CryptoKey.VersionTemplate.ProtectionLevel | String | The protection level describing how cryptographic operations are performed with this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.VersionTemplate.Algorithm | String | The CryptoKeyVersionAlgorithm that this CryptoKeyVersion supports. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.Name | String | The resource name for this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.State | String | The current state of the CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.CreationTime | Date | The time when this CryptoKeyVersion was created. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.ProtectionLevel | String | The ProtectionLevel describing how cryptographic operations are performed with this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.Algorithm | String | The algorithm in use in the primary CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.GenerateTime | Date | The time this CryptoKeyVersion’s key material was generated. |
google-kms-symmetric-decrypt
Decrypts data that was protected by Encrypt.
Base Command
google-kms-symmetric-decrypt
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical region where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to use. | Required |
| simple_ciphertext | The ciphertext to decrypt to simple plain text. | Optional |
| additional_authenticated_data | A base64-encoded string passed to Cloud KMS as part of an encrypt or decrypt request. The optional data that must match the data originally supplied in the EncryptRequest.additional_authenticated_data. |
Optional |
| base64_ciphertext | The ciphertext to decrypt to base64 plain text. | Optional |
| entry_id | The entry ID for the file to decrypt. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.SymmetricDecrypt.CryptoKey | String | The CryptoKey in use. |
| GoogleKMS.SymmetricDecrypt.IsBase64 | Boolean | Whether the original plain text is in base64. |
| GoogleKMS.SymmetricDecrypt.Plaintext | String | The decrypted plaintext. |
google-kms-symmetric-encrypt
Encrypts data, so it can only be recovered by a call to Decrypt.
Base Command
google-kms-symmetric-encrypt
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For example, https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to use. | Required |
| simple_plaintext | Simple plain text to encrypt. Must be no larger than 64KiB. | Optional |
| additional_authenticated_data | A base64-encoded string passed to Cloud KMS as part of an encrypt or decrypt request. Must also be provided during decryption through DecryptRequest.additional_authenticated_data. The maximum size depends on the key version’s protection level. For SOFTWARE keys, the AAD must be no larger than 64KiB. For HSM keys, the combined length of the plain text and additionalAuthenticatedData fields must be no larger than 8KiB. |
Optional |
| base64_plaintext | The Base64 plain text to encrypt. | Optional |
| entry_id | The entry ID for the file to encrypt. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.SymmetricEncrypt.CryptoKey | String | The CryptoKey used. |
| GoogleKMS.SymmetricEncrypt.IsBase64 | Boolean | Whether the original plain text is in base 64. |
| GoogleKMS.SymmetricEncrypt.Ciphertext | String | The encrypted ciphertext. |
google-kms-get-key
Returns metadata for a given CryptoKey, and its primary CryptoKeyVersion.
Base Command
google-kms-get-key
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For example, https://cloud.google.com/kms/docs/locations. Keyword ‘default’ sets the location to the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the fetched crypto-key. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.CryptoKey.Name | String | The resource name for this CryptoKey. |
| GoogleKMS.CryptoKey.Purpose | String | The immutable purpose of this CryptoKey. |
| GoogleKMS.CryptoKey.CreationTime | Date | The time at which this CryptoKey was created. |
| GoogleKMS.CryptoKey.NextRotationTime | Date | The date when the next scheduled rotation is due to run. At nextRotationTime, the Key Management Service automatically |
| creates a new version of this CryptoKey and marks the new version as primary. | ||
| GoogleKMS.CryptoKey.RotationPeriod | String | The period for which the nextRotationTime is advanced, when the service automatically rotates a key. hours. |
| GoogleKMS.CryptoKey.Labels | String | Labels with user-defined metadata. |
| GoogleKMS.CryptoKey.VersionTemplate.ProtectionLevel | String | The ProtectionLevel describing how cryptographic operations are performed with this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.VersionTemplate.Algorithm | String | The CryptoKeyVersionAlgorithm that this CryptoKeyVersion supports. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.Name | String | The resource name for this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.State | String | The current state of the CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.CreationTime | Date | The time at which this CryptoKeyVersion was created. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.ProtectionLevel | String | The ProtectionLevel describing how cryptographic operations are performed with this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.Algorithm | String | The algorithm used in the primary CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.GenerateTime | Date | The time this CryptoKeyVersion’s key material was generated. |
google-kms-update-key
Updates a CryptoKey.
Base Command
google-kms-update-key
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the updated crypto-key. | Required |
| next_rotation_time | The date when the next scheduled rotation is due to run. At nextRotationTime, the Key Management Service automatically creates a new version of this CryptoKey and marks the new version as primary. Key rotations performed manually via cryptoKeyVersions.create and cryptoKeys.updatePrimaryVersion do not affect nextRotationTime. Keys with purpose ENCRYPT_DECRYPT, support automatic rotation. For other keys, this field must be omitted. A timestamp or a date in RFC3339 UTC “Zulu” format, accurate to nanoseconds. For example, “2014-10-02T15:01:23.045123456Z”. |
Optional |
| attestation | Statement that was generated and signed by the HSM at key creation time. Use this statement to verify attributes of the key as stored on the HSM, independently of Google. Only provided for key versions with protectionLevel HSM. | Optional |
| state | The state of a CryptoKeyVersion, indicating if it can be used. Can be: “CRYPTO_KEY_VERSION_STATE_UNSPECIFIED, “PENDING_GENERATION”, “ENABLED”, “DISABLED”, “DESTROYED”, “DESTROY_SCHEDULED” , “PENDING_IMPORT”, “ IMPORT_FAILED”. Possible values are: CRYPTO_KEY_VERSION_STATE_UNSPECIFIED, PENDING_GENERATION, ENABLED, DISABLED, DESTROYED, DESTROY_SCHEDULED, PENDING_IMPORT, IMPORT_FAILED. | Optional |
| purpose | CryptoKeyPurpose describes the cryptographic capabilities of a CryptoKey. A given key can only be used for the operations allowed by its purpose. Can be: “CRYPTO_KEY_PURPOSE_UNSPECIFIED”, “ENCRYPT_DECRYPT”, “ASYMMETRIC_SIGN”, “ASYMMETRIC_DECRYPT”. Possible values are: CRYPTO_KEY_PURPOSE_UNSPECIFIED, ENCRYPT_DECRYPT, ASYMMETRIC_SIGN, ASYMMETRIC_DECRYPT. | Optional |
| rotation_period | Time between when new key versions are generated automatically. Must between 24 hours and 876,000 hours. If rotation_period is set, next_rotation_time must also be set. Keys with purpose ENCRYPT_DECRYPT support automatic rotation. For other keys, this field must be omitted. A duration in seconds. | Optional |
| algorithm | Algorithm to use when creating a CryptoKeyVersion based on this template. Possible values are: CRYPTO_KEY_VERSION_ALGORITHM_UNSPECIFIED, GOOGLE_SYMMETRIC_ENCRYPTION, RSA_SIGN_PSS_2048_SHA256, RSA_SIGN_PSS_3072_SHA256, RSA_SIGN_PSS_4096_SHA256, RSA_SIGN_PSS_4096_SHA512, RSA_SIGN_PKCS1_2048_SHA256, RSA_SIGN_PKCS1_3072_SHA256, RSA_SIGN_PKCS1_4096_SHA256, RSA_SIGN_PKCS1_4096_SHA512, RSA_DECRYPT_OAEP_2048_SHA256, RSA_DECRYPT_OAEP_3072_SHA256, RSA_DECRYPT_OAEP_4096_SHA256, RSA_DECRYPT_OAEP_4096_SHA512, EC_SIGN_P256_SHA256, EC_SIGN_P384_SHA384. | Optional |
| protection_level | The protection_level to use when creating a CryptoKeyVersion based on this template. Can be: “PROTECTION_LEVEL_UNSPECIFIED”, “SOFTWARE”, “HSM”. Possible values are: PROTECTION_LEVEL_UNSPECIFIED, SOFTWARE, HSM. | Optional |
| labels | Labels with user-defined metadata. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.CryptoKey.Name | String | The resource name for this CryptoKey. |
| GoogleKMS.CryptoKey.Purpose | String | The immutable purpose of this CryptoKey. |
| GoogleKMS.CryptoKey.CreationTime | String | The time at which this CryptoKey was created. |
| GoogleKMS.CryptoKey.NextRotationTime | Date | The date when the next scheduled rotation is due to run. At nextRotationTime, the Key Management Service automatically |
| creates a new version of this CryptoKey and marks the new version as primary. | ||
| GoogleKMS.CryptoKey.RotationPeriod | String | The period for which the nextRotationTime is advanced, when the service automatically rotates a key. |
| GoogleKMS.CryptoKey.Labels | String | Labels with user-defined metadata. |
| GoogleKMS.CryptoKey.VersionTemplate.ProtectionLevel | String | The ProtectionLevel describing how crypto operations are performed with this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.VersionTemplate.Algorithm | String | The CryptoKeyVersionAlgorithm that this CryptoKeyVersion supports. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.Name | String | The resource name for this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.State | String | The current state of the CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.CreationTime | Date | The time at which this CryptoKeyVersion was created. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.ProtectionLevel | String | The ProtectionLevel describing how cryptographic operations are performed with this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.Algorithm | String | The algorithm in use in the primary CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.GenerateTime | Date | The time this CryptoKeyVersion’s key material was generated. |
google-kms-destroy-key
Schedules a CryptoKeyVersion for destruction.
Base Command
google-kms-destroy-key
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For example, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to destroy. | Required |
| crypto_key_version | The CryptoKeyVersion ID to destroy. Use keyword ‘default’ to use the primary CryptoKeyVersion of the given CryptoKey. Default is default. | Required |
Context Output
There is no context output for this command.
google-kms-restore-key
Restores a CryptoKeyVersion in the DESTROY_SCHEDULED state.
Base Command
google-kms-restore-key
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For example, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to restore. | Required |
| crypto_key_version | The CryptoKeyVersion ID to restore. Use keyword ‘default’ to use the primary CryptoKeyVersion of the given CryptoKey. Default is default. | Required |
Context Output
There is no context output for this command.
google-kms-disable-key
Disables a CryptoKeyVersion of a given CryptoKey.
Base Command
google-kms-disable-key
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to disable. | Required |
| crypto_key_version | The CryptoKeyVersion ID to disable. Use keyword ‘default’ to use the primary CryptoKeyVersion of the given CryptoKey. Default is default. | Required |
Context Output
There is no context output for this command.
google-kms-enable-key
Enables a CryptoKeyVersion of a given CryptoKey.
Base Command
google-kms-enable-key
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to enable. | Required |
| crypto_key_version | The CryptoKeyVersion ID to enable. Use keyword ‘default’ to use the primary CryptoKeyVersion of the given CryptoKey. Default is default. | Required |
Context Output
There is no context output for this command.
google-kms-list-keys
Lists all keys in key ring.
Base Command
google-kms-list-keys
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| key_state | Shows only keys with this primary CryptoKeyVersion state. Leave empty to show all. Can be: “CRYPTO_KEY_VERSION_STATE_UNSPECIFIED”, “PENDING_GENERATION”, “ENABLED”, “DISABLED”, “DESTROYED”, “DESTROY_SCHEDULED”, “PENDING_IMPORT”, “IMPORT_FAILED”. Possible values are: CRYPTO_KEY_VERSION_STATE_UNSPECIFIED, PENDING_GENERATION, ENABLED, DISABLED, DESTROYED, DESTROY_SCHEDULED, PENDING_IMPORT, IMPORT_FAILED. | Optional |
Context Output
There is no context output for this command.
google-kms-asymmetric-encrypt
Encrypts data using a asymmetric CryptoKey
Base Command
google-kms-asymmetric-encrypt
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the location to the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to use. | Required |
| crypto_key_version | The CryptoKeyVersion to use. | Required |
| simple_plaintext | Simple plain text to encrypt. Must be no larger than 64KiB. | Optional |
| base64_plaintext | Base64 plain text to encrypt. | Optional |
| entry_id | The entry ID of the file to encrypt. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.AsymmetricEncrypt.CryptoKey | String | The CryptoKey used |
| GoogleKMS.AsymmetricEncrypt.IsBase64 | Boolean | Is the original plaintext in base 64 |
| GoogleKMS.AsymmetricEncrypt.Ciphertext | String | The encrypted ciphertext |
google-kms-asymmetric-decrypt
Decrypts data using an asymmetric CryptoKey.
Base Command
google-kms-asymmetric-decrypt
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to use. | Required |
| crypto_key_version | The CryptoKeyVersion to use. | Required |
| simple_ciphertext | Ciphertext to decrypt to simple plain text. | Optional |
| base64_ciphertext | Ciphertext to decrypt to base64 plain text. | Optional |
| entry_id | The entry ID of the file to decrypt. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.AsymmetricDecrypt.CryptoKey | String | The CryptoKey in use. |
| GoogleKMS.AsymmetricDecrypt.IsBase64 | Boolean | Whether the original plain text is in base64. |
| GoogleKMS.AsymmetricDecrypt.Plaintext | String | The decrypted plain text. |
google-kms-list-key-rings
Lists all KeyRings in a given location.
Base Command
google-kms-list-key-rings
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| all | Returns all KeyRings from all locations. Default is no. Possible values are: yes, no. Default is no. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.KeyRing.Name | String | The name of the KeyRing. |
| GoogleKMS.KeyRing.CreateTime | Date | The creation time of the KeyRing. |
google-kms-list-all-keys
Lists all CryptoKeys across all KeyRings in a given location.
Base Command
google-kms-list-all-keys
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| all | Whether to return all CryptoKeys from all KeyRings across all locations. Possible values are: yes, no. Default is no. | Optional |
| key_state | Shows only keys with this primary CryptoKeyVersion state. Leave empty to show all. Possible values are: CRYPTO_KEY_VERSION_STATE_UNSPECIFIED, PENDING_GENERATION, ENABLED, DISABLED, DESTROYED, DESTROY_SCHEDULED, PENDING_IMPORT, IMPORT_FAILED. | Optional |
Context Output
| Path | Type | Description |
| — | — | — |
| GoogleKMS.CryptoKey.Name | String | The resource name for this CryptoKey. |
| GoogleKMS.CryptoKey.Purpose | String | The immutable purpose of this CryptoKey. |
| GoogleKMS.CryptoKey.CreationTime | Date | The time at which this CryptoKey was created. |
| GoogleKMS.CryptoKey.NextRotationTime | Date | The date when the next scheduled rotation is due to run. At nextRotationTime, the Key Management Service automatically
creates a new version of this CryptoKey and
marks the new version as primary. |
| GoogleKMS.CryptoKey.RotationPeriod | String | The period for which the nextRotationTime is advanced, when the service automatically rotates a key. |
| GoogleKMS.CryptoKey.Labels | String | Labels with user-defined metadata. |
| GoogleKMS.CryptoKey.VersionTemplate.ProtectionLevel | String | The ProtectionLevel describing how crypto operations are performed with this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.VersionTemplate.Algorithm | String | The CryptoKeyVersionAlgorithm that this CryptoKeyVersion supports. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.Name | String | The resource name for this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.State | String | The current state of the CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.CreationTime | String | The time at which this CryptoKeyVersion was created. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.ProtectionLevel | String | The ProtectionLevel describing how crypto operations are performed with this CryptoKeyVersion. |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.Algorithm | String | The algorithm in use in the primary CryptoKeyVersion |
| GoogleKMS.CryptoKey.PrimaryCryptoKeyVersion.GenerateTime | Date | The time this CryptoKeyVersion’s key material was generated. |
google-kms-get-public-key
Returns the public key from a given CryptoKey.
Base Command
google-kms-get-public-key
Input
| Argument Name | Description | Required |
|---|---|---|
| location | The geographical regions where requests to Cloud KMS for a given resource are handled, and where the corresponding cryptographic keys are stored. For more information, see https://cloud.google.com/kms/docs/locations. Keyword ‘default’ uses the default location. Possible values are: default, global, asia-east1, asia-east2, asia-northeast1, asia-northeast2, asia-south1, asia-southeast1, australia-southeast1, europe-north1, europe-west1, europe-west2, europe-west3, europe-west4, europe-west6, northamerica-northeast1, us-central1, us-east1, us-east4, us-west1, us-west2, southamerica-east1, eur4, nam4, asia, europe, us. Default is default. |
Required |
| key_ring | A grouping of keys for organizational purposes. Keyword ‘default’ uses the default KeyRing. Default is default. |
Required |
| crypto_key | The ID for the crypto-key to use. | Required |
| crypto_key_version | The CryptoKeyVersion to use. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleKMS.PublicKey.CryptoKey | String | The CryptoKey to which the public key is connected. |
| GoogleKMS.PublicKey.PEM | String | The PEM of the public key. |
| GoogleKMS.PublicKey.Algorithm | String | The algorithm used in the CryptoKey |
Configuration parameters
service_account— User's Service Account JSONcredentials_service_account—project— Project in Google Cloud KMS (required)location— Default Location (required)key_ring— Default Key Ringproxy— Use system proxy settings
Commands (15)
-
google-kms-asymmetric-decryptDecrypts data using an asymmetric CryptoKey.
-
google-kms-asymmetric-encryptEncrypts data using a asymmetric CryptoKey.
-
google-kms-create-keyCreates a new CryptoKey within a KeyRing.
-
google-kms-destroy-keySchedules a CryptoKeyVersion for destruction.
-
google-kms-disable-keyDisables a CryptoKeyVersion of a given CryptoKey.
-
google-kms-enable-keyEnables a CryptoKeyVersion of a given CryptoKey.
-
google-kms-get-keyReturns metadata for a given CryptoKey, and its primary CryptoKeyVersion.
-
google-kms-get-public-keyReturns the public key from a given CryptoKey.
-
google-kms-list-all-keysLists all CryptoKeys across all KeyRings in a given location.
-
google-kms-list-key-ringsLists all KeyRings in a given location.
-
google-kms-list-keysLists all keys in key ring.
-
google-kms-restore-keyRestores a CryptoKeyVersion in the DESTROY_SCHEDULED state.
-
google-kms-symmetric-decryptDecrypts data that was protected by Encrypt.
-
google-kms-symmetric-encryptEncrypts data, so it can only be recovered by a call to Decrypt.
-
google-kms-update-keyUpdates a CryptoKey.
import demistomock as demisto from CommonServerPython import * from CommonServerUserPython import * """IMPORTS""" import base64 from json import JSONDecodeError from typing import Any from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding from google.cloud import kms # type: ignore[attr-defined] """ For further information about the API used in the integration see: 1) Google KMS API Client libraries information: https://cloud.google.com/kms/docs/reference/libraries 2) Git resource with some API use examples: https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/kms/api-client """ INTEGRATION_NAME = "Google Key Management System" # lowercase with `-` dividers INTEGRATION_COMMAND_NAME = "google-kms" # No dividers INTEGRATION_CONTEXT_NAME = "GoogleKMS" DEMISTO_DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S" RFC3339_DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" class Client: def __init__(self, params: dict[str, Any]): self.project = params.get("project") self.location = params.get("location") self.key_ring = params.get("key_ring") self.service_account = params.get("credentials_service_account", {}).get("password") or params.get("service_account") if not self.service_account: raise DemistoException("User's Service Account JSON must be provided.") handle_proxy() # Creates an API client for the KMS API. try: self.kms_client = self._init_kms_client() except JSONDecodeError: raise Exception("Service Account json has missing details. You need to re-create the json file.") def _init_kms_client(self): """Creates the Python API client for Google Cloud KMS using service account credentials.""" dictionary_test = json.loads(str(self.service_account)) if not isinstance(dictionary_test, dict): raise Exception("Service Account json is not formatted well. You need to change the json file.") credentials_file_name = demisto.uniqueFile() + ".json" credentials_file_path = os.path.join(os.getcwd(), credentials_file_name) with open(credentials_file_path, "w") as creds_file: json_object = json.loads(str(self.service_account)) json.dump(json_object, creds_file) return kms.KeyManagementServiceClient.from_service_account_json(filename=credentials_file_path) # type: ignore[call-arg] """HELPER FUNCTIONS""" def get_timestamp_seconds(date): if not date: return 0 if isinstance(date, timedelta): seconds = date.total_seconds() else: seconds = str(date.timestamp()).split(".")[0] # type: ignore[assignment] return seconds def get_timestamp_nanoseconds(date): if not date: return 0 return str(date.timestamp()).split(".")[1] def arg_dict_creator(string: Any): """Creates a Dict from a CSV string. Args: string(str): CSV string - formatted as 'field1:value1,field2:value2'. Returns: Dict from string representation. """ if not string: return None split_string = string.split(",") arg_dict = {} for section in split_string: section_key, section_value = section.split(":", 1) arg_dict[section_key] = section_value return arg_dict def clear_label_commas(labels: Any): """When extracted from the response - the labels return with an added commas and spaces This function removes these commas. Args: labels(Dict): a dictionary of labels as returned from the response. Returns: the label dictionary without the commas and spaces. """ if not labels: return None cleared_labels = {} # type:Dict for label in labels: # A label key can come in the form of: 'info' or _'info' (with an extra space) # The following check is whether to drop the first 2 characters or just one if str(label).startswith(" "): cleared_label_key = label[2:-1] else: cleared_label_key = label[1:-1] if str(labels[label]).startswith(" "): cleared_label_value = labels[label][2:-1] else: cleared_label_value = labels[label][1:-1] cleared_labels[cleared_label_key] = cleared_label_value return cleared_labels def key_context_creation(res: Any, project_id: str, location_id: str, key_ring_id: str) -> dict: """Creates GoogleKMS.CryptoKey context. Args: res(Any): `~google.cloud.kms.CryptoKey` instance. project_id(str): the project id location_id(str): the location id key_ring_id(str): the KeyRing id Returns: Dict representing GoogleKMS.CryptoKey context. """ # remove the CryptoKey path and leave only the name pre_name = f"projects/{project_id}/locations/{location_id}/keyRings/{key_ring_id}/cryptoKeys/" name = str(res.name).replace(pre_name, "") # prepare the labels labels = str(res.labels) if labels != "{}": labels = arg_dict_creator(str(labels)[1:-1]) labels = clear_label_commas(labels) else: labels = "" key_context = { "Name": name, "Project": project_id, "Location": location_id, "KeyRing": key_ring_id, "Purpose": kms.CryptoKey.CryptoKeyPurpose(res.purpose).name, "CreationTime": datetime.fromtimestamp(int(get_timestamp_seconds(res.create_time))).strftime(DEMISTO_DATETIME_FORMAT), "NextRotationTime": datetime.fromtimestamp(int(get_timestamp_seconds(res.next_rotation_time))).strftime( DEMISTO_DATETIME_FORMAT ), "RotationPeriod": f"{get_timestamp_seconds(res.rotation_period)!s}s", "Labels": labels, "VersionTemplate": { "ProtectionLevel": kms.ProtectionLevel(res.version_template.protection_level).name, "Algorithm": kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm(res.version_template.algorithm).name, }, } # if primary CryptoKeyVersion exists and is returned create context for it. # Note: As part of the API - Asymmetric keys do not return primary CryptoKeyVersion info. if res.primary and res.primary.name and len(res.primary.name) > 0: key_context["PrimaryCryptoKeyVersion"] = { "Name": res.primary.name, "State": kms.CryptoKeyVersion.CryptoKeyVersionState(res.primary.state).name, "CreationTime": datetime.fromtimestamp(int(get_timestamp_seconds(res.primary.create_time))).strftime( DEMISTO_DATETIME_FORMAT ), "ProtectionLevel": kms.ProtectionLevel(res.primary.protection_level).name, "Algorithm": kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm(res.primary.algorithm).name, "GenerateTime": datetime.fromtimestamp(int(get_timestamp_seconds(res.primary.generate_time))).strftime( DEMISTO_DATETIME_FORMAT ), } return key_context def crypto_key_to_json(crypto_key: Any) -> dict: """Creates a json dict from `~google.cloud.kms.CryptoKey` instance to use as raw response. Args: crypto_key(Any): `~google.cloud.kms.CryptoKey` instance. Returns: A json Dict containing the raw response. """ # handle labels labels = str(crypto_key.labels) if labels != "{}": labels = arg_dict_creator(str(labels)[1:-1]) labels = clear_label_commas(labels) else: labels = "" key_json = { "name": crypto_key.name, "purpose": kms.CryptoKey.CryptoKeyPurpose(crypto_key.purpose).name, "create_time": { "seconds": get_timestamp_seconds(crypto_key.create_time), "nanos": get_timestamp_nanoseconds(crypto_key.create_time), }, "next_rotation_time": { "seconds": get_timestamp_seconds(crypto_key.next_rotation_time), "nanos": get_timestamp_nanoseconds(crypto_key.next_rotation_time), }, "rotation_period": {"seconds": get_timestamp_seconds(crypto_key.rotation_period)}, "labels": labels, "version_template": { "protection_level": kms.ProtectionLevel(crypto_key.version_template.protection_level).name, "algorithm": kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm(crypto_key.version_template.algorithm).name, }, } if crypto_key.primary: key_json["primary"] = { "name": crypto_key.primary.name, "state": kms.CryptoKeyVersion.CryptoKeyVersionState(crypto_key.primary.state).name, "create_time": { "seconds": get_timestamp_seconds(crypto_key.primary.create_time), "nanos": get_timestamp_nanoseconds(crypto_key.primary.create_time), }, "protection_level": kms.ProtectionLevel(crypto_key.primary.protection_level).name, "algorithm": kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm(crypto_key.primary.algorithm).name, "generate_time": { "seconds": get_timestamp_seconds(crypto_key.primary.generate_time), "nanos": get_timestamp_nanoseconds(crypto_key.primary.generate_time), }, } return key_json def demisto_args_extract(client: Client, args: dict[str, Any]) -> tuple[str, str, str, str]: """Extracts IDs to use for KMS functions. Args: args(dict): Demisto arguments. client(Client): User Client. Returns: A tuple containing strings representing the required IDs. """ project_id = client.project location_id = args.get("location") if location_id == "default": location_id = client.location key_ring_id = args.get("key_ring") if key_ring_id == "default": key_ring_id = client.key_ring crypto_key_id = args.get("crypto_key") return str(project_id), str(location_id), str(key_ring_id), str(crypto_key_id) def get_update_mask(args: dict[str, Any]) -> dict: """Creates the 'updateMask' parameter for the command which is a comma separated list of fields to update. Args: args(dict): Demisto args indicating which field to update. Returns: A Dict to use as the params for update command. """ update_mask = [] if args.get("labels") is not None: update_mask.append("labels") if args.get("next_rotation_time") is not None: update_mask.append("next_rotation_time") if args.get("purpose") is not None: update_mask.append("purpose") if args.get("rotation_period") is not None: update_mask.append("rotation_period") if args.get("attestation") is not None: update_mask.append("primary.attestation") if args.get("state") is not None: update_mask.append("primary.state") if args.get("algorithm") is not None: update_mask.append("version_template.algorithm") if args.get("protection_level") is not None: update_mask.append("version_template.protection_level") return {"paths": update_mask} def get_update_command_body(args: dict[str, Any], update_mask: list) -> dict: """Creates update command request body, in accordance with the updateMask. Args: args(Dict): Demisto arguments containing the updated values. update_mask(List): List of fields to update. Returns: Dict to be used as body for update command """ body = {} # type:Dict[str,Any] if "labels" in update_mask: # Add label dictionary to body body["labels"] = arg_dict_creator(args.get("labels")) if "next_rotation_time" in update_mask: if str(args.get("next_rotation_time")).isdigit(): # If next_rotation_time given is a timestamp enter it as is body["next_rotation_time"] = {"seconds": int(str(args.get("next_rotation_time")))} else: # If next_rotation_time is date string, convert it to timestamp body["next_rotation_time"] = { "seconds": int(datetime.strptime(str(args.get("next_rotation_time")), RFC3339_DATETIME_FORMAT).timestamp()) } if "purpose" in update_mask: # Add purpose enum to body body["purpose"] = kms.CryptoKey.CryptoKeyPurpose[args["purpose"]].value # type: ignore[misc] if "rotation_period" in update_mask: # Add rotation_period to body body["rotation_period"] = {"seconds": int(str(args.get("rotation_period")))} if "primary.attestation" in update_mask or "primary.state" in update_mask: # Init the 'primary' sub-dictionary body["primary"] = {} if "primary.attestation" in update_mask: # Add attestation dict to 'primary' sub-dictionary body["primary"]["attestation"] = arg_dict_creator(args.get("attestation")) if "primary.state" in update_mask: # Add state enum to 'primary' sub-dictionary body["primary"]["state"] = kms.CryptoKeyVersion.CryptoKeyVersionState[args.get("state")].value # type: ignore[misc] if "version_template.algorithm" in update_mask or "version_template.protection_level" in update_mask: # Init the 'version_template' sun-dictionary body["version_template"] = {} if "version_template.algorithm" in update_mask: # Add algorithm enum to 'version_template' sun-dictionary val = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm[args["algorithm"]].value # type: ignore[misc] body["version_template"]["algorithm"] = val if "version_template.protection_level" in update_mask: # Add protection_level to 'version_template' sun-dictionary val = kms.ProtectionLevel[args["protection_level"]].value # type: ignore[misc] body["version_template"]["protection_level"] = val return body def get_primary_key_version(project_id: str, location_id: str, key_ring_id: str, crypto_key_id: str, client: Client) -> str: """Return primary CryptoKeyVersion of a given CryptoKey. Args: project_id(str): Project of the CryptoKey. location_id(str): Location the CryptoKey is assigned to. key_ring_id(str): Key Ring in which the CryptoKey exists. crypto_key_id(str): The CryptoKey id. client(Client): User's Client. Returns: A string with the full path to the primary CryptoKeyVersion """ # The resource name of the CryptoKey. crypto_key_name = client.kms_client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # Get the CryptoKey and extract it's primary version path. crypto_key = client.kms_client.get_crypto_key(request={"name": crypto_key_name}) if crypto_key.primary.name is None: raise Exception(f"CryptoKey {crypto_key_name} has no primary CryptoKeyVersion") return str(crypto_key.primary.name) def key_ring_context_and_json_creation(key_ring: Any) -> tuple[dict, dict]: key_ring_context = { "Name": key_ring.name, "CreateTime": datetime.fromtimestamp(int(key_ring.create_time.timestamp())).strftime(DEMISTO_DATETIME_FORMAT), } key_ring_json = { "name": key_ring.name, "create_time": { "seconds": int(get_timestamp_seconds(key_ring.create_time)), "nanos": int(get_timestamp_nanoseconds(key_ring.create_time)), }, } return key_ring_context, key_ring_json """GENERAL FUNCTIONS""" def create_crypto_key_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, dict]: """Create a new CryptoKey. Args: client(Client): User Client. args(Dict): Demisto arguments. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) # The resource name of the KeyRing associated with the CryptoKey. key_ring_name = client.kms_client.key_ring_path(project_id, location_id, key_ring_id) if args.get("next_rotation_time"): # change next_rotation time from date to timestamp if needed. if not str(args.get("next_rotation_time")).isdigit(): next_rotation_time = { "seconds": int(datetime.strptime(str(args.get("next_rotation_time")), RFC3339_DATETIME_FORMAT).timestamp()) } else: next_rotation_time = {"seconds": int(str(args.get("next_rotation_time")))} else: # if not next rotation time given - set it to 90 days from now (default by Google) next_rotation_time = {"seconds": int((datetime.now() + timedelta(days=90)).timestamp())} # Create the CryptoKey object template crypto_key = { "purpose": kms.CryptoKey.CryptoKeyPurpose[args.get("purpose")].value, # type: ignore[misc] "next_rotation_time": next_rotation_time, "labels": arg_dict_creator(args.get("labels")), "rotation_period": {"seconds": int(str(args.get("rotation_period")))}, } # Additional info in case CryptoKeyVersion is created if args.get("skip_initial_version_creation") != "true": crypto_key["primary"] = { "state": kms.CryptoKeyVersion.CryptoKeyVersionState[args.get("state")].value, # type: ignore[misc] "attestation": arg_dict_creator(args.get("attestation")), } crypto_key["version_template"] = { "algorithm": kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm[args.get("algorithm")].value, # type: ignore[misc] "protection_level": kms.ProtectionLevel[args.get("protection_level")].value, # type: ignore[misc] } # Create a CryptoKey for the given KeyRing. response = client.kms_client.create_crypto_key( request={ "parent": key_ring_name, "crypto_key_id": crypto_key_id, "crypto_key": crypto_key, "skip_initial_version_creation": args.get("skip_initial_version_creation") == "true", } ) context = key_context_creation(response, project_id, location_id, key_ring_id) headers = [ "CreationTime", "Name", "Project", "Location", "KeyRing", "Labels", "NextRotationTime", "Purpose", "RotationPeriod", "PrimaryCryptoKeyVersion", "VersionTemplate", ] return ( tableToMarkdown("Google KMS CryptoKey info:", context, removeNull=True, headers=headers), { f"{INTEGRATION_CONTEXT_NAME}.CryptoKey(val.Name == obj.Name)": context, }, crypto_key_to_json(response), ) def symmetric_encrypt_key_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """Encrypt plaintext to ciphertext using a symmetric key. Args: client(Client): User Client. args(Dict): Demisto arguments. Returns: The encrypted ciphertext. """ # handle given plaintext - revert it to base 64. if args.get("simple_plaintext"): plaintext = base64.b64encode(bytes(str(args.get("simple_plaintext")), "utf-8")) elif args.get("base64_plaintext"): plaintext = base64.b64decode(str(args.get("base64_plaintext"))) elif args.get("entry_id"): file = demisto.getFilePath(args.get("entry_id")) file_path = file["path"] with open(file_path, "rb") as fp: plaintext = base64.b64encode(fp.read()) else: raise ValueError("No object to encrypt.") project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) additional_authenticated_data = None if args.get("additional_authenticated_data"): additional_authenticated_data = base64.b64decode(str(args.get("additional_authenticated_data"))) # The resource name of the CryptoKey. crypto_key_name = client.kms_client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # Use the KMS API to encrypt the data. response = client.kms_client.encrypt( request={"name": crypto_key_name, "plaintext": plaintext, "additional_authenticated_data": additional_authenticated_data} ) # return the created ciphertext cleaned from additional characters. ciphertext = str(base64.b64encode(response.ciphertext))[2:-1] symmetric_encrypt_context = { "CryptoKey": crypto_key_id, "IsBase64": args.get("base64_plaintext") is not None, "Ciphertext": ciphertext, } if args.get("entry_id"): file_name = demisto.getFilePath(args.get("entry_id"))["name"] + "_encrypted.txt" demisto.results(fileResult(file_name, ciphertext)) return ( f"The text has been encrypted.\nCiphertext: {ciphertext}", { f"{INTEGRATION_CONTEXT_NAME}.SymmetricEncrypt(val.CryptoKey == obj.CryptoKey " f"&& val.IsBase64 == obj.IsBase64 && val.Ciphertext == obj.Ciphertext)": symmetric_encrypt_context, }, symmetric_encrypt_context, ) def symmetric_decrypt_key_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """Decrypt ciphertext to plaintext using a symmetric key. Args: client(Client): User Client. args(Dict): Demisto agruments. Returns: The decrypted text. """ if args.get("simple_ciphertext"): ciphertext = base64.b64decode(str(args.get("simple_ciphertext"))) elif args.get("base64_ciphertext"): ciphertext = base64.b64decode(str(args.get("base64_ciphertext"))) elif args.get("entry_id"): file = demisto.getFilePath(args.get("entry_id")) file_path = file["path"] with open(file_path, "rb") as fp: ciphertext = base64.b64decode(fp.read()) else: raise ValueError("No object to decrypt.") project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) additional_authenticated_data = None if args.get("additional_authenticated_data"): additional_authenticated_data = base64.b64decode(str(args.get("additional_authenticated_data"))) # The resource name of the CryptoKey. crypto_key_name = client.kms_client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # Use the KMS API to decrypt the data. response = client.kms_client.decrypt( request={ "name": crypto_key_name, "ciphertext": ciphertext, "additional_authenticated_data": additional_authenticated_data, } ) # handle the resulting plain text if it supposed to be in base64 and clean added characters. if args.get("base64_ciphertext"): plaintext = str(base64.b64encode(response.plaintext))[2:-1].replace("\\n", "\n") elif args.get("simple_ciphertext") or args.get("entry_id"): plaintext = str(base64.b64decode(response.plaintext))[2:-1].replace("\\n", "\n") else: plaintext = "" demisto.debug(f"The arguments didn't match any condition, {plaintext=}") if args.get("entry_id"): file_name = demisto.getFilePath(args.get("entry_id"))["name"] + "_decrypted.txt" demisto.results(fileResult(file_name, plaintext)) symmetric_decrypt_context = { "CryptoKey": crypto_key_id, "IsBase64": args.get("base64_ciphertext") is not None, "Plaintext": plaintext, } return ( f"The text has been decrypted.\nPlaintext: {plaintext}", { f"{INTEGRATION_CONTEXT_NAME}.SymmetricDecrypt(val.CryptoKey == obj.CryptoKey " f"&& val.IsBase64 == obj.IsBase64 && val.Plaintext == obj.Plaintext)": symmetric_decrypt_context, }, symmetric_decrypt_context, ) def get_key_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, dict]: """Gets a CryptoKey. Args: client(Client): User Client. args(Dict): Demisto Arguments. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) # The resource name of the CryptoKey. crypto_key_name = client.kms_client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # Get CryptoKey info. response = client.kms_client.get_crypto_key(request={"name": crypto_key_name}) context = key_context_creation(response, project_id, location_id, key_ring_id) headers = [ "CreationTime", "Name", "Project", "Location", "KeyRing", "Labels", "NextRotationTime", "Purpose", "RotationPeriod", "PrimaryCryptoKeyVersion", "VersionTemplate", ] return ( tableToMarkdown("Google KMS CryptoKey info:", context, removeNull=True, headers=headers), { f"{INTEGRATION_CONTEXT_NAME}.CryptoKey(val.Name == obj.Name)": context, }, crypto_key_to_json(response), ) def disable_key_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """Disable a given CryptoKeyVersion. Args: client(Client): User Client. args(Dict): Demisto arguments. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) crypto_key_version = args.get("crypto_key_version") if crypto_key_version == "default": # if no CryptoKeyVersion given extract the primary CryptoKeyVersion. crypto_key_version_name = get_primary_key_version(project_id, location_id, key_ring_id, crypto_key_id, client) else: # Construct the resource name of the CryptoKeyVersion. crypto_key_version_name = client.kms_client.crypto_key_version_path( project_id, location_id, key_ring_id, crypto_key_id, crypto_key_version ) # if not CryptoKeyVersion is given nor was is extracted from the CryptoKey - raise error to the user. if crypto_key_version_name is None or len(crypto_key_version_name) == 0: raise Exception("Please insert primary CryptoKeyVersion ID") # Use the KMS API to disable the CryptoKeyVersion. new_state = kms.CryptoKeyVersion.CryptoKeyVersionState.DISABLED version = {"name": crypto_key_version_name, "state": new_state} update_mask = {"paths": ["state"]} # Print results response = client.kms_client.update_crypto_key_version(request={"crypto_key_version": version, "update_mask": update_mask}) return ( f"CryptoKeyVersion {crypto_key_version_name}'s state has been set to " f"{kms.CryptoKeyVersion.CryptoKeyVersionState(response.state).name}.", None, None, ) def enable_key_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """Enable a CryptoKeyVersion. Args: client(Client): User Client. args(Dict): Demisto arguments. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) crypto_key_version = args.get("crypto_key_version") if crypto_key_version == "default": # if no CryptoKeyVersion given extract the primary CryptoKeyVersion. crypto_key_version_name = get_primary_key_version(project_id, location_id, key_ring_id, crypto_key_id, client) else: # Construct the resource name of the CryptoKeyVersion. crypto_key_version_name = client.kms_client.crypto_key_version_path( project_id, location_id, key_ring_id, crypto_key_id, crypto_key_version ) # if not CryptoKeyVersion is given nor was is extracted from the CryptoKey - raise error to the user. if crypto_key_version_name is None or len(crypto_key_version_name) == 0: raise Exception("Please insert primary CryptoKeyVersion ID") # Use the KMS API to enable the CryptoKeyVersion. new_state = kms.CryptoKeyVersion.CryptoKeyVersionState.ENABLED version = {"name": crypto_key_version_name, "state": new_state} update_mask = {"paths": ["state"]} # Print results response = client.kms_client.update_crypto_key_version(request={"crypto_key_version": version, "update_mask": update_mask}) return ( f"CryptoKeyVersion {crypto_key_version_name}'s state has been set to " f"{kms.CryptoKeyVersion.CryptoKeyVersionState(response.state).name}.", None, None, ) def destroy_key_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """Schedule the destruction of a given CryptoKeyVersion. Args: client(Client): User Client. args(Dict): Demisto arguments. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) crypto_key_version = args.get("crypto_key_version") if crypto_key_version == "default": # if no CryptoKeyVersion given extract the primary CryptoKeyVersion. crypto_key_version_name = get_primary_key_version(project_id, location_id, key_ring_id, crypto_key_id, client) else: # Construct the resource name of the CryptoKeyVersion. crypto_key_version_name = client.kms_client.crypto_key_version_path( project_id, location_id, key_ring_id, crypto_key_id, crypto_key_version ) # if not CryptoKeyVersion is given nor was is extracted from the CryptoKey - raise error to the user. if crypto_key_version_name is None or len(crypto_key_version_name) == 0: raise Exception("Please insert primary CryptoKeyVersion ID") # Use the KMS API to mark the CryptoKeyVersion for destruction. response = client.kms_client.destroy_crypto_key_version(request={"name": crypto_key_version_name}) # Print results return ( f"CryptoKeyVersion {crypto_key_version_name}'s state has been set to " f"{kms.CryptoKeyVersion.CryptoKeyVersionState(response.state).name}, it will be destroyed in 24h.", None, None, ) def restore_key_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """Restores a CryptoKeyVersion scheduled for destruction. Args: client(Client): User Client. args(Dict): Demisto arguments. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) crypto_key_version = args.get("crypto_key_version") if crypto_key_version == "default": # if no CryptoKeyVersion given extract the primary CryptoKeyVersion. crypto_key_version_name = get_primary_key_version(project_id, location_id, key_ring_id, crypto_key_id, client) else: # Construct the resource name of the CryptoKeyVersion. crypto_key_version_name = client.kms_client.crypto_key_version_path( project_id, location_id, key_ring_id, crypto_key_id, crypto_key_version ) # if not CryptoKeyVersion is given nor was is extracted from the CryptoKey - raise error to the user. if crypto_key_version_name is None or len(crypto_key_version_name) == 0: raise Exception("Please insert primary CryptoKeyVersion ID") # Use the KMS API to restore the CryptoKeyVersion. response = client.kms_client.restore_crypto_key_version(request={"name": crypto_key_version_name}) # Print results return ( f"CryptoKeyVersion {crypto_key_version_name}'s state has been set to " f"{kms.CryptoKeyVersion.CryptoKeyVersionState(response.state).name}.", None, None, ) def update_key_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, dict]: """Update a given CryptoKey. Args: client(Client): User Client. args(Dict): Demisto arguments. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) # The resource name of the CryptoKey. crypto_key_name = client.kms_client.crypto_key_path(project_id, location_id, key_ring_id, crypto_key_id) # create a list of fields to be updated using the command - the field is called update mask in the API. update_mask = get_update_mask(args) # create the body of the update request. crypto_key = get_update_command_body(args=args, update_mask=update_mask["paths"]) crypto_key["name"] = crypto_key_name # update command using the KMS API. response = client.kms_client.update_crypto_key(request={"crypto_key": crypto_key, "update_mask": update_mask}) context = key_context_creation(response, project_id, location_id, key_ring_id) headers = [ "CreationTime", "Name", "Project", "Location", "KeyRing", "Labels", "NextRotationTime", "Purpose", "RotationPeriod", "PrimaryCryptoKeyVersion", "VersionTemplate", ] return ( tableToMarkdown("Google KMS CryptoKey info:", context, removeNull=True, headers=headers), { f"{INTEGRATION_CONTEXT_NAME}.CryptoKey(val.Name == obj.Name)": context, }, crypto_key_to_json(response), ) def list_keys_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, list]: """List All keys in a KeyRing. Args: client(Client): User Client. args(Dict): Demisto arguments. """ project_id, location_id, key_ring_id, _ = demisto_args_extract(client, args) # Get the full path to the KeyRing in which to list the keys. key_ring_name = client.kms_client.key_ring_path(project_id, location_id, key_ring_id) # if needed add state filter. filter_state = args.get("key_state", None) response = client.kms_client.list_crypto_keys(request={"parent": key_ring_name, "filter": filter_state}) overall_context = [] # type: List overall_raw = [] # type: List for crypto_key in response: overall_context.append(key_context_creation(crypto_key, project_id, location_id, key_ring_id)) overall_raw.append(crypto_key_to_json(crypto_key)) headers = [ "CreationTime", "Name", "Project", "Location", "KeyRing", "Labels", "NextRotationTime", "Purpose", "RotationPeriod", "PrimaryCryptoKeyVersion", "VersionTemplate", ] return ( tableToMarkdown(name="CryptoKeys:", t=overall_context, removeNull=True, headers=headers), { f"{INTEGRATION_CONTEXT_NAME}.CryptoKey(val.Name == obj.Name)": overall_context, }, overall_raw, ) def asymmetric_encrypt_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """Encrypt plainttext using an asymmetric key. Args: client(Client): User's client. args(dict): Demisto arguments. Returns: The encrypted ciphertext. """ # handle the plaintext - convert to base64 if args.get("simple_plaintext"): plaintext = base64.b64encode(bytes(str(args.get("simple_plaintext")), "utf-8")) elif args.get("base64_plaintext"): plaintext = base64.b64decode(str(args.get("base64_plaintext"))) elif args.get("entry_id"): file = demisto.getFilePath(args.get("entry_id")) file_path = file["path"] with open(file_path, "rb") as fp: plaintext = base64.b64encode(fp.read()) else: raise ValueError("No object to encrypt.") project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) crypto_key_version = args.get("crypto_key_version") # Construct the resource name of the CryptoKeyVersion. crypto_key_version_name = client.kms_client.crypto_key_version_path( project_id, location_id, key_ring_id, crypto_key_id, crypto_key_version ) # get the CryptoKeyVersion info and check it's algorithm. crypto_key_version_info = client.kms_client.get_crypto_key_version(request={"name": crypto_key_version_name}) key_algo = kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm(crypto_key_version_info.algorithm).name # Algorithm must be a "DECRYPT" type asymmetric algorithm - if not, raise an error to the user. if "DECRYPT" not in key_algo: raise ValueError(f"{crypto_key_version_name} is not a valid asymmetric CryptoKeyVersion") # get public key of the asymmetric encryption. public_key_response = client.kms_client.get_public_key(request={"name": crypto_key_version_name}) key_txt = public_key_response.pem.encode("ascii") public_key = serialization.load_pem_public_key(key_txt, default_backend()) # using the CryptoKeyVersion algorithm - create the necessary padding for the encryption. if "SHA256" in key_algo: # create padding with SHA256 pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None) else: # create padding with SHA512 pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA512()), algorithm=hashes.SHA512(), label=None) # encrypt plaintext and return the cipertext without added characters. ciphertext = str(base64.b64encode(public_key.encrypt(plaintext, pad)))[2:-1] # type: ignore[union-attr] asymmetric_encrypt_context = { "CryptoKey": crypto_key_id, "IsBase64": args.get("base64_plaintext") is not None, "Ciphertext": ciphertext, } if args.get("entry_id"): file_name = demisto.getFilePath(args.get("entry_id"))["name"] + "_encrypted.txt" demisto.results(fileResult(file_name, ciphertext)) return ( f"The text has been encrypted.\nCiphertext: {ciphertext}", { f"{INTEGRATION_CONTEXT_NAME}.AsymmetricEncrypt(val.CryptoKey == obj.CryptoKey " f"&& val.IsBase64 == obj.IsBase64 && val.Ciphertext == obj.Ciphertext)": asymmetric_encrypt_context, }, asymmetric_encrypt_context, ) def asymmetric_decrypt_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """Decrypt chipertext to plaintext using asymmetric key. Args: client(Client): User's Client. args(dict): Demisto arguments. Returns: The decrypted plaintext. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) crypto_key_version = args.get("crypto_key_version") # Construct the resource name of the CryptoKeyVersion. crypto_key_version_name = client.kms_client.crypto_key_version_path( project_id, location_id, key_ring_id, crypto_key_id, crypto_key_version ) if args.get("simple_ciphertext"): ciphertext = base64.b64decode(str(args.get("simple_ciphertext"))) elif args.get("base64_ciphertext"): ciphertext = base64.b64decode(str(args.get("base64_ciphertext"))) elif args.get("entry_id"): file = demisto.getFilePath(args.get("entry_id")) file_path = file["path"] with open(file_path, "rb") as fp: ciphertext = base64.b64decode(fp.read()) else: raise ValueError("No object to decrypt.") response = client.kms_client.asymmetric_decrypt(request={"name": crypto_key_version_name, "ciphertext": ciphertext}) # handle the created plaintext back to base64 if needed and clear added characters. if args.get("base64_ciphertext"): plaintext = str(base64.b64encode(response.plaintext))[2:-1].replace("\\n", "\n") elif args.get("simple_ciphertext") or args.get("entry_id"): plaintext = str(base64.b64decode(response.plaintext))[2:-1].replace("\\n", "\n") else: plaintext = "" demisto.debug(f"The arguments didn't match any condition, {plaintext=}") if args.get("entry_id"): file_name = demisto.getFilePath(args.get("entry_id"))["name"] + "_decrypted.txt" demisto.results(fileResult(file_name, plaintext)) asymmetric_decrypt_context = { "CryptoKey": crypto_key_id, "IsBase64": args.get("base64_ciphertext") is not None, "Plaintext": plaintext, } return ( f"The text has been decrypted.\nPlaintext: {plaintext}", { f"{INTEGRATION_CONTEXT_NAME}.AsymmetricDecrypt(val.CryptoKey == obj.CryptoKey " f"&& val.IsBase64 == obj.IsBase64 && val.Plaintext == obj.Plaintext)": asymmetric_decrypt_context, }, asymmetric_decrypt_context, ) def list_key_rings_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """List all KeyRings in a given location Args: client(Client): User's client. args(dict): Demisto args. """ # listing the KeyRings in order to check responses from the API. locations = [] if args.get("location") == "default": locations.append(client.location) else: locations.append(args.get("location")) # paramater 'all' checks all possible locations if args.get("all") == "yes": locations = [ "global", "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-south1", "asia-southeast1", "australia-southeast1", "europe-north1", "europe-west1", "europe-west2", "europe-west3", "europe-west4", "europe-west6", "northamerica-northeast1", "us-central1", "us-east1", "us-east4", "us-west1", "us-west2", "southamerica-east1", "eur4", "nam4", "asia", "europe", "us", ] key_rings_context = [] key_rings_json = [] for location in locations: location_path = f"projects/{client.project}/locations/{location}" # the response is a iterable containing the KeyRings info. response = client.kms_client.list_key_rings(request={"parent": location_path}) for key_ring in list(response): single_context, single_json = key_ring_context_and_json_creation(key_ring) key_rings_context.append(single_context) key_rings_json.append(single_json) return ( tableToMarkdown(name="KeyRings:", t=key_rings_context, removeNull=True), {f"{INTEGRATION_CONTEXT_NAME}.KeyRing(val.Name == obj.Name)": key_rings_context}, key_rings_json, ) def list_all_keys_command(client: Client, args: dict[str, Any]) -> tuple[str, Any, Any]: """List all CryptokKeys across all KeyRings in a given location. Args: client(Client): User's client. args(dict): Demisto args. """ locations = [] if args.get("location") == "default": locations.append(client.location) else: locations.append(args.get("location")) # paramater 'all' checks all possible locations if args.get("all") == "yes": locations = [ "global", "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-south1", "asia-southeast1", "australia-southeast1", "europe-north1", "europe-west1", "europe-west2", "europe-west3", "europe-west4", "europe-west6", "northamerica-northeast1", "us-central1", "us-east1", "us-east4", "us-west1", "us-west2", "southamerica-east1", "eur4", "nam4", "asia", "europe", "us", ] keys_context = [] keys_json = [] filter_state = args.get("key_state") for location in locations: location_path = f"projects/{client.project}/locations/{location}" # the response is a iterable containing the KeyRings info. response = client.kms_client.list_key_rings(request={"parent": location_path}) for key_ring in list(response): key_ring_name = key_ring.name pre_name = f"projects/{client.project}/locations/{location}/keyRings/" key_ring_id = str(key_ring_name).replace(pre_name, "") crypto_key_response = client.kms_client.list_crypto_keys(request={"parent": key_ring_name, "filter": filter_state}) for crypto_key in crypto_key_response: keys_context.append(key_context_creation(crypto_key, str(client.project), str(location), str(key_ring_id))) keys_json.append(crypto_key_to_json(crypto_key)) headers = [ "CreationTime", "Name", "Project", "Location", "KeyRing", "Labels", "NextRotationTime", "Purpose", "RotationPeriod", "PrimaryCryptoKeyVersion", "VersionTemplate", ] return ( tableToMarkdown(name="CryptoKeys:", t=keys_context, removeNull=True, headers=headers), { f"{INTEGRATION_CONTEXT_NAME}.CryptoKey(val.Name == obj.Name && val.Location == obj.Location" f"&& val.KeyRing == obj. KeyRing)": keys_context, }, keys_json, ) def get_public_key_command(client: Client, args: dict[str, Any]) -> tuple[str, dict, dict]: """Get the public key from an asymmetric CryptoKey Args: client(Client): User's client. args(dict): Demisto args. """ project_id, location_id, key_ring_id, crypto_key_id = demisto_args_extract(client, args) crypto_key_version = args.get("crypto_key_version") # Construct the resource name of the CryptoKeyVersion. crypto_key_version_name = client.kms_client.crypto_key_version_path( project_id, location_id, key_ring_id, crypto_key_id, crypto_key_version ) public_key_response = client.kms_client.get_public_key(request={"name": crypto_key_version_name}) public_key_context = { "CryptoKey": crypto_key_id, "PEM": str(public_key_response.pem), "Algorithm": kms.CryptoKeyVersion.CryptoKeyVersionAlgorithm(public_key_response.algorithm).name, } return ( f"The Public Key for CryptoKey {crypto_key_id} is:\n{public_key_context.get('PEM')}", {f"{INTEGRATION_CONTEXT_NAME}.PublicKey(val.CryptoKey == obj.CryptoKey && val.PEM == obj.PEM": public_key_context}, public_key_context, ) def test_function(client: Client) -> None: """Test's user's input this checks if the given service account has any of the required permissions to use the integration In client creation we check that the entered service account is a valid json and has all the required fields to create the client. In this function we try and get a response from Google KMS just to make sure we can connect to it. This test does NOT check if the service account has the required permissions to get a VALID response from KMS. Args: client(Client): User Client. """ # creating a valid resource name if client.key_ring: key_ring = client.key_ring else: key_ring = "random" key_ring_name = client.kms_client.key_ring_path(client.project, client.location, key_ring) client.kms_client.list_crypto_keys(request={"parent": key_ring_name}) def main(): COMMANDS = { f"{INTEGRATION_COMMAND_NAME}-create-key": create_crypto_key_command, f"{INTEGRATION_COMMAND_NAME}-symmetric-decrypt": symmetric_decrypt_key_command, f"{INTEGRATION_COMMAND_NAME}-symmetric-encrypt": symmetric_encrypt_key_command, f"{INTEGRATION_COMMAND_NAME}-get-key": get_key_command, f"{INTEGRATION_COMMAND_NAME}-update-key": update_key_command, f"{INTEGRATION_COMMAND_NAME}-destroy-key": destroy_key_command, f"{INTEGRATION_COMMAND_NAME}-restore-key": restore_key_command, f"{INTEGRATION_COMMAND_NAME}-disable-key": disable_key_command, f"{INTEGRATION_COMMAND_NAME}-enable-key": enable_key_command, f"{INTEGRATION_COMMAND_NAME}-list-keys": list_keys_command, f"{INTEGRATION_COMMAND_NAME}-asymmetric-encrypt": asymmetric_encrypt_command, f"{INTEGRATION_COMMAND_NAME}-asymmetric-decrypt": asymmetric_decrypt_command, f"{INTEGRATION_COMMAND_NAME}-list-key-rings": list_key_rings_command, f"{INTEGRATION_COMMAND_NAME}-list-all-keys": list_all_keys_command, f"{INTEGRATION_COMMAND_NAME}-get-public-key": get_public_key_command, } command = demisto.command() LOG(f"{INTEGRATION_NAME}: command is {command}") try: client = Client(demisto.params()) if command == "test-module": test_function(client) demisto.results("ok") if command not in COMMANDS: raise NotImplementedError(f'Command "{command}" is not implemented.') cmd_func = COMMANDS.get(command) # type: ignore results = cmd_func(client, demisto.args()) # type: ignore return_outputs(*results) except Exception as e: return_error(f"{INTEGRATION_NAME}: {e!s}", e) if __name__ in ["__main__", "builtin", "builtins"]: main()