Internal Blockchain: To Be or Not to Be?
During our recent hackathon held in Baltimore, one of our challenges was to use blockchain for data privacy and to ensure orders/payment/customer-profile transactions for backend systems were encrypted, secure and compliant.
One of the guys on our team had mentioned that this was not a great use case for blockchain — we were not mining, we were not using a peer-to-peer networking. What consensus mechanism were we going to use (i.e proof of work, proof of state etc.)? It made no sense to use it all. While my first reaction was to agree with him, upon re-thinking the solution to our problem, I really felt that there was a use case. Here’s why:
Snapshot from IBM’s “What is blockchain”
- Distributed ledger technology
- Records are immutable
- Smart contracts
(“Case for internal blockchain” — read the full article here https://medium.com/hashreader/the-case-for-your-internal-blockchain-strategy-c1217254c5c4)
In Summary:
Blockchain versus database
- Why not just store heavily encrypted data in a database? Well if I have admin access, and can change audits and data, it’s a no-brainer, blockchain is immutable and tamper-proof as it is a distributed ledger system.
Analysing the internal corporate blockchain strategy
We will have big wins on :
- Speed
- Security
- Privacy and Access
- Cost Benefit
So here is my proposed internal blockchain solution:
We can set up various blockchain “buckets” for payments, orders, customer details, cancellations, refunds (the latter two would require different backend verification and workflow implementation). We have a simple blockchain microservice (I built an initial POC using golang) and deployed it on Openshift (read more about Openshift here — it’s really enterprise Kubernetes)
The important part is the utility microservice. It has an embedded key pair (private and public) in the container with strict permission settings. This misroservice exposes an endpoint API for users to push data to the blockchain. To access this service, a short lived JWT (json web token is issued via an oauth service — not implemented yet)
All blockchain data is persisted to local file storage (within the container) and also saved to a document store (read only) for all users except for the blockchain microservice. This adds another layer for data distribution and security.
The service has the following encryption flow (see diagram):
The data is encrypted with the AES-CFB, the AES key is signed with the sender’s private key and finally, the AES key is encrypted with the receiver’s public key, making the whole process very difficult to decrypt. The data is then pushed to the blockchain with the previous and next hashes being updated accordingly (the blockchain microservice initialises with a “genesis” hash).
Even if the keys are compromised, it would be extremely difficult to change or tamper with the blockchain as we make use of distributed data sources and verification processes.
So the main problem becomes: how do we distribute the public keys? Remember we never reveal or expose our private keys, these remain on the server/machine when created and locked down with tight permissions.
The best way is to use QKD (quantum key distribution), outside of the classic channel, when we enquired about setting up a test lab, the costs were above 180K USD. This won’t work for small startups or smaller companies.
A solution I came up with was as follows: use a tcp client (this will reside on the admin/client’s system) with an embedded tcp server, deployed alongside the blockchain-insert microservice. It uses TLS edge termination in the Openshift cluster for secure tcp connections.
The blockchain-insert service has a RestFUL API point which sets the time the tcp server should start, as well as a random socket it should use.
This is initiated by the client (backend admin using a simple script). The TCP Server will start up at the given time, using the “oc command line tool” a route is exposed to allow the service to connect to the random port (we know what the port number is)
The client then connects to the tcp server and the following exchange happens.
- The client reads its public key
- The client then sends the public key to the server
- The server reads and saves the client’s public key
- The server reads its public key
- The server responds to the client with its public key
- The client saves the server’s public key
- The connections are closed and won’t be used until new keys are created
- The exposed route is deleted
I have managed to get the POC working using a set of simple bash scripts and a visual web page of the blockchain payload for now, (I’m looking at an electron desktop application for the client). The server side (microservices) were deployed on Openshift Online.
Payload in the blockchain service
{
"name": "Blockchain",
"statuscode": "200",
"status": "OK",
"message": "Blockchain list processed succesfully",
"blockchain": [
{
"index": 2,
"metainfo": "Microservice Blockchain Insert",
"objecta": "YuKUVFsEGGJjmm+TxDaTMpNfntWt5UhnhviYwCsRD6C3W8QVhAeznE+5EDeOK8/r3Lpjy9piY9T1b59si3gor5KYWHMCumK3ChjwPoq/T9Dl1X73YB1gzHWTy+p70av74+E6hSDT7Ua9n3Lw2cTBZSM8s8M8rSAtaCJHjM3isHrltVN1eUmUi5sH5xCKEN8WR4631yrlz6paOShuExYxXJj4CEUyhTmYGEky6zTMMkJM5XcEQ5dMx96zQeJHA4Qt02nFuk2sxNqdWC0ySuZ3ykQv+Z/gRou452wIXHk7irE4MB35EXYs+TBj0hUF8v4G+j++vFQ4uv03+q/d8j5gvA==",
"objectb": "fedfa1c4300e6d829e1dccc129ecf018be471bebd915636e5b4e0721a384f2c0e5bdd2eb18f425aa333f5673d129d1f00c00cbb1",
"objectc": "60c3b8c05a6dc97d58e96bd8dd0d46828ef752247c8dff4e580b7d50dc39134ab31555795ec80b1330880bfb92519ead1973cfb8ddb608460ceba7d3d1a224ef8845f51a7827c1b2b2250a6bec7f77345ab62528c4079d9b1e0691aab4e7eb0ce3fcf7124a5fd2f6d52dd231682e4a9611169f08d93f1f5059a897855ccee41e4149d1efb7f4e052fda64e3b4bff617942e4fe2badc3d462782cc4b5f4d488d82bff5442bc3f4276a1bbb43867768c9f41260edda547f73debd2dd7255620c17a41378e8f9b09a22f782dc612c1ce160b541ec2452c30dfd5b6ece45542138516cd17e0b1a480dc066480fa51e9fcbca139df7e9454e4a7dcaa28dca0bbe1609",
"timestamp": "2020-03-05 16:04:11.496752204 +0000 UTC m=+67055.766649167",
"hash": "a3ff978057e20e437b886ab3914a1ce6b9a777ca54ec8a50a83c2e4de0b6b482",
"prevhash": "7da8be4204cef07c26d677fe4e2172386c8a5ef176b2074a325d1256b8bbd72d"
}
]
}
The screenshot below shows the exchange (from the client to the server — localhost testing)
2020/03/18 09:40:42 [INFO] : client: connected to: 127.0.0.1:8000
[48 130 1 34 48 13 6 9 42 134 72 134 247 13 1 1 1 5 0 3 130 1 15 0 48 130 1 10 2 130 1 1 0 189 222 230 168 31 136 22 64 213 239 95 218 19 134 246 181 89 1 14 30 162 59 1 108 239 22 51 86 68 226 224 22 195 249 164 236 19 94 39 203 187 94 46 72 244 81 70 80 121 183 108 211 18 207 82 40 201 111 124 78 1 127 85 18 94 198 217 37 137 167 237 130 244 134 84 48 11 34 185 38 252 238 120 142 239 220 242 91 232 35 108 126 182 29 170 36 46 108 208 156 134 3 67 45 104 42 105 96 26 234 43 48 180 44 165 232 201 223 135 249 174 218 211 29 67 7 165 45 107 199 38 65 18 236 226 246 170 245 28 232 252 13 114 101 129 126 93 213 206 27 165 163 11 55 231 69 250 199 214 143 73 101 23 220 137 121 217 169 106 232 227 7 123 183 44 139 165 87 246 135 23 32 140 137 156 152 115 98 85 232 226 193 156 135 66 152 190 35 177 217 88 208 55 22 24 149 27 116 224 101 178 128 39 96 226 152 25 12 80 92 66 154 224 119 164 29 238 140 119 227 36 46 90 69 94 14 240 98 36 106 32 73 76 104 252 211 13 173 204 18 56 227 38 136 49 15 2 3 1 0 1] <nil>
CN=www.random.com,OU=IT,O=Prv Company,L=Ireland,ST=WATERFORD,C=IE
2020/03/18 09:40:42 [INFO] : client: handshake: true
2020/03/18 09:40:42 [INFO] : client: mutual: true
2020/03/18 09:40:42 [INFO] : client: wrote: "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAstYPMb58GB90CuVOIq/r\nw2yBldwClcYbtZV6Up4TAleTDbbTfRGIW637f1aLg5qauwG8HKv3pIQ2qXx4yP4v\nYPVjzwLHTHokdFLhc+GV7VD0O0UijYn81rez6YIR2TMHeUC/H8/TjLi8bID1Fpoc\nmzh2OniV8xEFvxicebiVYtnnAdRgYkQ0TGz6oiAJ8cFdwPDbUHQLRfUs3R2ngdJE\n18kcDNFmelac1A/7emEmKCp7TzZ9JETksTOJTHHbHqYFUHXfYxtb5u5sYhnYiEZa\naE5I7h08UXFHFx1dcaHsuesMOADSgJQoaKswKLF4DXGuXQCePEcwr163hvHbo7IZ\nlwIDAQAB\n-----END RSA PUBLIC KEY-----\n" (459 bytes)
2020/03/18 09:40:42 [INFO] : client: read: "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwthpT3KhkYO2ezB2Sw2F\nLqtRSrmxW8A+6PpYnicvnVgp4eKqX1P0fp8pKi7qG5uYB6+PU0JQwQJV2bTfO6zS\nG8PIXFyNDLTNs55tiWdEoOKBEFojXsbtZixEvEWc9SE+/XbSzWU+/7jSWF9PXti3\nUB21hckTbmpomrp6l8te5ugb++d5AqaNRhmRoRD7kSe8aQCEUGBJOrYHOkLAY4++\n2HoSrU/0EuTq2OQaNSn5/dKQ1aN0HHejskbIVtM58aBG7DKAyaqk+txP2ngZgSsG\nESaLPxr+govHwFLuYCXLpwkg6AtsktzUzk6rv6Af789c0rznbIncgFCtO/U/zhRF\nVQIDAQAB\n-----END RSA PUBLIC KEY-----\n" (459 bytes)
2020/03/18 09:40:42 [INFO] : client: exiting
It’s not the optimal solution for key distribution but it does make it extremely difficult to hack.
Next Steps
- Replicate blockchain data across various Availability Zones, flat file and indexed NoSql databases
- Improve UI functionality (search, view, query)
- An approved internal consensus mechanism.
- Implement backend workflows for both cancellations and refunds.
- Add client services seamlessly (for data decryption).
- Performance testing.
- Improve the tcp key distribution (use ssh tunnels) on local machines with random ports. This requires port forwarding on the Openshift cluster but would need cluster-admin roles and firewall rules to be set.
Summary
The big win though is that we have internal blockchain “buckets” with hardened secured data that cannot be easily tampered with.
Above all, I had great fun in playing around with blockchain, AES and RSA encryption/decryption, self signed CA certs, tcp services, linux containers, golang and Openshift.