Tracking activity in Amazon Managed Blockchain with Amazon CloudWatch Logs

AWS recently launched a new integration between Amazon Managed Blockchain and Amazon CloudWatch. You can now benefit from detailed logs showing important activity in your blockchain networks, including activity in your member certificate authority (CA), Hyperledger Fabric peer nodes, and chaincode.

This post shows how to use these new features to track blockchain activity in your decentralized apps. It also discusses how to create alarms in Amazon CloudWatch to notify you of blockchain activity.

Enabling logging in Amazon Managed Blockchain

Before you get started, set up your blockchain network and Fabric client with logging enabled in Amazon CloudWatch Logs. For more information, see Monitoring Blockchain Activity Using CloudWatch Logs.

There are two places where you can enable logging. When you add a member to a blockchain network, you now have the option to enable logging on the member’s certificate authority (CA) service. See the following screenshot.

Enabling any of the logging options creates a log group named /aws/managedblockchain/<NetworkID>/<MemberID>. If you enable CA logging, you see a log stream under this group called ca. This log stream contains detailed logs of all activity related to the CA.

You can also enable logging when you create a peer node. You have the option to enable detailed logs that show all activity on the node (peer node logs) or logs created by your chaincode. See the following screenshot.

Chaincode logs can help you track important activity in your business workflows. The CA and peer node logs can help you troubleshoot complex interactions between Fabric components to get insights into your particular workloads.

Adding log messages to chaincode

The chaincode logs feature can be especially useful for tracking important activity in your business workflows. This post demonstrates how to use logs to verify that only users with the appropriate permissions can run chaincode invocations and to raise alerts when a user attempts unauthorized access. To test these features and enable a CloudWatch alarm to notify you of any unauthorized access attempts, deploy the following code in your network. Save the following code in your Fabric client’s home folder in /home/ec2-user/permissions-example/index.js:

/////////////////////////////////////////////////////////
// ROLE-BASED ACCESS CONTROL EXAMPLE
// 
// The following chaincode demonstrates how to prevent
// unauthorized clients from invoking chaincode methods.
/////////////////////////////////////////////////////////

'use strict';
const shim = require('fabric-shim');

/////////////////////////////////////////////////////////
// requireRole
//
// This method will throw an error if the calling client
// does not have the specified role.
/////////////////////////////////////////////////////////
async function requireRole(stub, role) {
  const ClientIdentity = shim.ClientIdentity;
  let cid = new ClientIdentity(stub);
  if (!cid.assertAttributeValue('role', role))
    throw new Error(`Unauthorized access: ${role} required`);
}

let Chaincode = class {
  async Init(stub) {
    console.info('============= Init called =============');
    return shim.success();
  }

  async Invoke(stub) {
    console.info('============= Invoke called =============');
    
    // ensure client has admin role before proceeding
    try {
      await requireRole(stub, 'admin');
    } catch(err) {
      // log failed access attempt and return
      console.error("Error during Invoke: ", err);
      return shim.error(err.message || err);
    }
    
    // client has the expected role, so continue
    console.info('SUCCESS!')
    return shim.success();
  }
}

shim.start(new Chaincode());

You also need to store the following dependency declaration in /home/ec2-user/permissions-example/package.json:

{
  "name": "permissions",
  "version": "0.1",
  "description": "Chaincode for testing user permissions",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "start": "node index.js"
  },
  "dependencies": {
    "fabric-shim": "^1.2.4"
  }
}

Deploying and testing your chaincode

Deploy the chaincode and test to see if your invocations fail the permission test as expected:

[ec2-user@ip-XXX-XX-XX-XXX ~]$ docker exec cli peer chaincode install -n perms -v 0.1 -l node -p /opt/home/permissions-example
2020-02-26 02:19:51.499 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2020-02-26 02:19:51.499 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2020-02-26 02:19:51.500 UTC [container] WriteFolderToTarPackage -> INFO 003 rootDirectory = /opt/home/permissions-example
2020-02-26 02:19:51.505 UTC [chaincodeCmd] install -> INFO 004 Installed remotely response:<status:200 payload:"OK" >
[ec2-user@ip-XXX-XX-XX-XXX ~]$ docker exec cli peer chaincode instantiate -o $ORDERER -C mychannel -n perms -v 0.1 -l node -c '{"Args": ["init"]}' --cafile /opt/home/managedblockchain-tls-chain.pem --tls
2020-02-26 02:20:03.558 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2020-02-26 02:20:03.558 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
[ec2-user@ip-XXX-XX-XX-XXX ~]$ docker exec cli peer chaincode query -C mychannel -n perms -c '{"Args": ["invoke"]}' -o $ORDERER --cafile /opt/home/managedblockchain-tls-chain.pem --tls
Error: endorsement failure during query. response: status:500 message:"transaction returned with failure: Unauthorized access: admin required"

If all goes as expected, you should see a permissions error in your chaincode, as in the preceding code example. This is because you called your chaincode with the default Fabric client identity, which doesn’t have a role attribute assigned to it yet.

Generating a new client identity with the necessary permissions

In this next step, you generate a client certificate and key with the proper role attribute. This post uses a simple password. In your own environment, use a unique and secure password. See the following commands and resulting output:

[ec2-user@ip-XXX-XX-XX-XXX ~]$ fabric-ca-client register --id.name superuser --id.affiliation member1 --tls.certfiles /home/ec2-user/managedblockchain-tls-chain.pem --id.type user --id.secret Password123 --id.attrs "role=admin:ecert"
2020/02/26 02:31:00 [INFO] Configuration file location: /home/ec2-user/.fabric-ca-client/fabric-ca-client-config.yaml
2020/02/26 02:31:00 [INFO] TLS Enabled
2020/02/26 02:31:00 [INFO] TLS Enabled
Password: Password123
[ec2-user@ip-XXX-XX-XX-XXX ~]$ fabric-ca-client enroll -u https://superuser:Password123@$CASERVICEENDPOINT --tls.certfiles /home/ec2-user/managedblockchain-tls-chain.pem -M /home/ec2-user/superuser-msp
2020/02/26 02:35:04 [INFO] TLS Enabled
2020/02/26 02:35:04 [INFO] generating key: &{A:ecdsa S:256}
2020/02/26 02:35:04 [INFO] encoded CSR
2020/02/26 02:35:04 [INFO] Stored client certificate at /home/ec2-user/superuser-msp/signcerts/cert.pem
2020/02/26 02:35:04 [INFO] Stored root CA certificate at /home/ec2-user/superuser-msp/cacerts/ca-m-sercxjlv7zdg5pjn76hwx6iahu-n-qcid77fovbeideo2wyuvvomdpa-managedblockchain-us-east-1-amazonaws-com-30002.pem
[ec2-user@ip-XXX-XX-XX-XXX ~]$ cp -r admin-msp/admincerts/ superuser-msp

After you create the identity, copy the intermediate certificates from another identity to make sure that your new certificate has all the necessary information to be used in your chaincode operations.

You can now use this new identity to invoke your chaincode and see if it passes the permissions check successfully. Override the default setting for environment variable CORE_PEER_MSPCONFIGPATH so that the Fabric client uses your new certificate as the client identity instead of the default. See the following command:

[ec2-user@ip-XXX-XX-XX-XXX ~]$ docker exec -e "CORE_PEER_MSPCONFIGPATH=/opt/home/superuser-msp" cli peer chaincode query -C mychannel -n perms -c '{"Args": ["invoke"]}' -o $ORDERER --cafile /opt/home/managedblockchain-tls-chain.pem --tls

Inside your CloudWatch log, you should see the SUCCESS! debug output.

Setting up CloudWatch alarms

As a final step, you can set up a CloudWatch alarm for whenever an unauthorized user tries to invoke your chaincode. To do this, make sure you enabled the new CloudWatch interface by choosing Try the new design for Amazon CloudWatch Logs.

  1. On the CloudWatch Logs console, choose View log groups.
  2. Select the log group for your blockchain member.
  3. On the Metric filters tab, choose Create metric filter.
  4. Define a filter pattern and test it on an example of your chaincode’s log stream.
  5. After you make sure the filter works, choose Next.
  1. Enter the following information:
    • A filter name.
    • A namespace where this filter is grouped.
    • A metric name (this can be the same as the filter name).
    • A value of 1 for the metric value
    • A value of 0 for the default value.
  2. Choose Next, then Create metric filter.
    You return to the list of metric filters, where you see the filter you just created.
  3. Select your new filter and choose Create alarm.
  1. To receive a notification of every unauthorized access attempt, provide the following:
    • Choose Minimum for the statistic.
    • Leave the period at 5 minutes.
    • Leave the threshold static.
    • Set the alarm condition to Greater than 0.
  2. Choose Next.
  3. Under Alarm state trigger, select In alarm.
  4. Choose Create new topic.
  5. Enter a topic name and an email for notifications.
  6. Choose Create topic.
    You see a prompt to name your alarm.
  7. Enter a name and choose Next.
  8. Choose Create alarm.
  9. Choose the confirmation link on the email that you receive.
    You can then repeat the process of making an unauthorized chaincode invocation and confirm that you receive notification via email.

Summary

This post demonstrated how to enable CloudWatch Logs on your blockchain network, deploy chaincode to the network, and used chaincode logs to monitor unauthorized access. You also learned how to generate additional certificate attributes for your network users and how to set up CloudWatch alarms to alert you automatically when certain important conditions occur in your workloads. Please share your experiences of building on Amazon Managed Blockchain and any questions or feature requests in the comments section.

 


About the Author

 

Carl Youngblood is a Blockchain Solutions Architect with Amazon Web Services.