diff --git a/etc/cowrie.cfg.dist b/etc/cowrie.cfg.dist index f4a1c859..3f46f671 100644 --- a/etc/cowrie.cfg.dist +++ b/etc/cowrie.cfg.dist @@ -1066,3 +1066,22 @@ api_key = abcdef1234567890fedcba0987654321 ddsource = cowrie ddtags = env:dev service = honeypot + +# Oracle Cloud custom logs output module +# sends JSON directly to Oracle Cloud custom logs +# mandatory field: authtype, log_ocid +# optional fields (to be set if user_principals is selected as authtype): user_ocid, fingerprint, tenancy_ocid, region, keyfile +# For more information on Oracle Cloud custom logs: https://docs.oracle.com/en-us/iaas/Content/Logging/Concepts/custom_logs.htm +# For more information on Oracle Cloud user principal authentication method: https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm#five +# For more information on Oracle Cloud instance principal authentication method: https://blogs.oracle.com/developers/post/accessing-the-oracle-cloud-infrastructure-api-using-instance-principals +[output_oraclecloud] +enabled = false +# authtype must be set either to user_principals or to instance_principals +authtype = instance_principals +# following parameters must be set in case user_principals is used. keyfile is the absolute path to your API pem key file. +#log_ocid = ocid1.log.oc1.eu-stockholm-1.xxx +#user_ocid = ocid1.user.oc1..xxx +#fingerprint = 77:9c:4xxxxx +#tenancy_ocid = ocid1.tenancy.oc1..xxx +#region = eu-stockholm-1 +#keyfile = /home/xx/key.pem diff --git a/requirements-output.txt b/requirements-output.txt index 37f9c608..f7309fd5 100644 --- a/requirements-output.txt +++ b/requirements-output.txt @@ -38,3 +38,5 @@ pymisp==2.4.178 # redis redis==5.0.1 +# Oracle Cloud +oci==2.115.1 diff --git a/src/cowrie/output/oraclecloud.py b/src/cowrie/output/oraclecloud.py new file mode 100644 index 00000000..db369d22 --- /dev/null +++ b/src/cowrie/output/oraclecloud.py @@ -0,0 +1,102 @@ +from __future__ import annotations + +import datetime +import json +import secrets +import string + +import oci + +from twisted.python import log + +import cowrie.core.output +from cowrie.core.config import CowrieConfig + + +class Output(cowrie.core.output.Output): + """ + Oracle Cloud output + """ + def generate_random_log_id(self): + charset = string.ascii_letters + string.digits + random_log_id = "".join(secrets.choice(charset) for _ in range(32)) + return f"cowrielog-{random_log_id}" + + def sendLogs(self, logentry): + log_id = self.generate_random_log_id() + # Initialize service client with default config file + current_time = datetime.datetime.utcnow() + self.log_ocid = CowrieConfig.get("output_oraclecloud", "log_ocid") + self.hostname = CowrieConfig.get("honeypot", "hostname") + + try: + # Send the request to service, some parameters are not required, see API + # doc for more info + self.loggingingestion_client.put_logs( + log_id=self.log_ocid, + put_logs_details=oci.loggingingestion.models.PutLogsDetails( + specversion="1.0", + log_entry_batches=[ + oci.loggingingestion.models.LogEntryBatch( + entries=[ + oci.loggingingestion.models.LogEntry( + data=logentry, + id=log_id, + time=current_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ"))], + source=self.hostname, + type="cowrie")]), + timestamp_opc_agent_processing=current_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")) + except oci.exceptions.ServiceError as ex: + log.err( + f"Oracle Cloud plugin Error: {ex.message}\n" + + f"Oracle Cloud plugin Status Code: {ex.status}\n" + ) + except Exception as ex: + log.err(f"Oracle Cloud plugin Error: {ex}") + raise + + def start(self): + """ + Initialize Oracle Cloud LoggingClient with user or instance principal authentication + """ + authtype=CowrieConfig.get("output_oraclecloud", "authtype") + + if authtype == "instance_principals": + signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner() + + # In the base case, configuration does not need to be provided as the region and tenancy are obtained from the InstancePrincipalsSecurityTokenSigner + # identity_client = oci.identity.IdentityClient(config={}, signer=signer) + self.loggingingestion_client = oci.loggingingestion.LoggingClient(config={}, signer=signer) + + elif authtype == "user_principals": + tenancy_ocid=CowrieConfig.get("output_oraclecloud", "tenancy_ocid") + user_ocid=CowrieConfig.get("output_oraclecloud", "user_ocid") + region=CowrieConfig.get("output_oraclecloud", "region") + fingerprint=CowrieConfig.get("output_oraclecloud", "fingerprint") + keyfile=CowrieConfig.get("output_oraclecloud", "keyfile") + + config_with_key_content = { + "user": user_ocid, + "key_file": keyfile, + "fingerprint": fingerprint, + "tenancy": tenancy_ocid, + "region": region + } + oci.config.validate_config(config_with_key_content) + self.loggingingestion_client = oci.loggingingestion.LoggingClient(config_with_key_content) + else: + raise ValueError("Invalid authentication type") + + def stop(self): + pass + + def write(self, logentry): + """ + Push to Oracle Cloud put_logs + """ + # Add the entry to redis + for i in list(logentry.keys()): + # Remove twisted 15 legacy keys + if i.startswith("log_"): + del logentry[i] + self.sendLogs(json.dumps(logentry))