github.com/niluplatform/go-nilu@v1.7.4-0.20200912082737-a0cb0776d52c/cmd/clef/docs/setup.md (about) 1 # Setting up Clef 2 3 This document describes how Clef can be used in a more secure manner than executing it from your everyday laptop, 4 in order to ensure that the keys remain safe in the event that your computer should get compromised. 5 6 ## Qubes OS 7 8 9 ### Background 10 11 The Qubes operating system is based around virtual machines (qubes), where a set of virtual machines are configured, typically for 12 different purposes such as: 13 14 - personal 15 - Your personal email, browsing etc 16 - work 17 - Work email etc 18 - vault 19 - a VM without network access, where gpg-keys and/or keepass credentials are stored. 20 21 A couple of dedicated virtual machines handle externalities: 22 23 - sys-net provides networking to all other (network-enabled) machines 24 - sys-firewall handles firewall rules 25 - sys-usb handles USB devices, and can map usb-devices to certain qubes. 26 27 The goal of this document is to describe how we can set up clef to provide secure transaction 28 signing from a `vault` vm, to another networked qube which runs Dapps. 29 30 ### Setup 31 32 There are two ways that this can be achieved: integrated via Qubes or integrated via networking. 33 34 35 #### 1. Qubes Integrated 36 37 Qubes provdes a facility for inter-qubes communication via `qrexec`. A qube can request to make a cross-qube RPC request 38 to another qube. The OS then asks the user if the call is permitted. 39 40 ![Example](qubes/qrexec-example.png) 41 42 A policy-file can be created to allow such interaction. On the `target` domain, a service is invoked which can read the 43 `stdin` from the `client` qube. 44 45 This is how [Split GPG](https://www.qubes-os.org/doc/split-gpg/) is implemented. We can set up Clef the same way: 46 47 ##### Server 48 49 ![Clef via qrexec](qubes/clef_qubes_qrexec.png) 50 51 On the `target` qubes, we need to define the rpc service. 52 53 [qubes.Clefsign](qubes/qubes.Clefsign): 54 55 ```bash 56 #!/bin/bash 57 58 SIGNER_BIN="/home/user/tools/clef/clef" 59 SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN" 60 61 # Start clef if not already started 62 if [ ! -S /home/user/.clef/clef.ipc ]; then 63 $SIGNER_CMD & 64 sleep 1 65 fi 66 67 # Should be started by now 68 if [ -S /home/user/.clef/clef.ipc ]; then 69 # Post incoming request to HTTP channel 70 curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null 71 fi 72 73 ``` 74 This RPC service is not complete (see notes about HTTP headers below), but works as a proof-of-concept. 75 It will forward the data received on `stdin` (forwarded by the OS) to Clef's HTTP channel. 76 77 It would have been possible to send data directly to the `/home/user/.clef/.clef.ipc` 78 socket via e.g `nc -U /home/user/.clef/clef.ipc`, but the reason for sending the request 79 data over `HTTP` instead of `IPC` is that we want the ability to forward `HTTP` headers. 80 81 To enable the service: 82 83 ``` bash 84 sudo cp qubes.Clefsign /etc/qubes-rpc/ 85 sudo chmod +x /etc/qubes-rpc/ qubes.Clefsign 86 ``` 87 88 This setup uses [gtksigner](https://github.com/holiman/gtksigner), which is a very minimal GTK-based UI that works well 89 with minimal requirements. 90 91 ##### Client 92 93 94 On the `client` qube, we need to create a listener which will receive the request from the Dapp, and proxy it. 95 96 97 [qubes-client.py](qubes/client/qubes-client.py): 98 99 ```python 100 101 """ 102 This implements a dispatcher which listens to localhost:8550, and proxies 103 requests via qrexec to the service qubes.EthSign on a target domain 104 """ 105 106 import http.server 107 import socketserver,subprocess 108 109 PORT=8550 110 TARGET_DOMAIN= 'debian-work' 111 112 class Dispatcher(http.server.BaseHTTPRequestHandler): 113 def do_POST(self): 114 post_data = self.rfile.read(int(self.headers['Content-Length'])) 115 p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE) 116 output = p.communicate(post_data)[0] 117 self.wfile.write(output) 118 119 120 with socketserver.TCPServer(("",PORT), Dispatcher) as httpd: 121 print("Serving at port", PORT) 122 httpd.serve_forever() 123 124 125 ``` 126 127 #### Testing 128 129 To test the flow, if we have set up `debian-work` as the `target`, we can do 130 131 ```bash 132 $ cat newaccnt.json 133 { "id": 0, "jsonrpc": "2.0","method": "account_new","params": []} 134 135 $ cat newaccnt.json| qrexec-client-vm debian-work qubes.Clefsign 136 ``` 137 138 This should pop up first a dialog to allow the IPC call: 139 140 ![one](qubes/qubes_newaccount-1.png) 141 142 Followed by a GTK-dialog to approve the operation 143 144 ![two](qubes/qubes_newaccount-2.png) 145 146 To test the full flow, we use the client wrapper. Start it on the `client` qube: 147 ``` 148 [user@work qubes]$ python3 qubes-client.py 149 ``` 150 151 Make the request over http (`client` qube): 152 ``` 153 [user@work clef]$ cat newaccnt.json | curl -X POST -d @- http://localhost:8550 154 ``` 155 And it should show the same popups again. 156 157 ##### Pros and cons 158 159 The benefits of this setup are: 160 161 - This is the qubes-os intended model for inter-qube communication, 162 - and thus benefits from qubes-os dialogs and policies for user approval 163 164 However, it comes with a couple of drawbacks: 165 166 - The `qubes-gpg-client` must forward the http request via RPC to the `target` qube. When doing so, the proxy 167 will either drop important headers, or replace them. 168 - The `Host` header is most likely `localhost` 169 - The `Origin` header must be forwarded 170 - Information about the remote ip must be added as a `X-Forwarded-For`. However, Clef cannot always trust an `XFF` header, 171 since malicious clients may lie about `XFF` in order to fool the http server into believing it comes from another address. 172 - Even with a policy in place to allow rpc-calls between `caller` and `target`, there will be several popups: 173 - One qubes-specific where the user specifies the `target` vm 174 - One clef-specific to approve the transaction 175 176 177 #### 2. Network integrated 178 179 The second way to set up Clef on a qubes system is to allow networking, and have Clef listen to a port which is accessible 180 form other qubes. 181 182 ![Clef via http](qubes/clef_qubes_http.png) 183 184 185 186 187 ## USBArmory 188 189 The [USB armory](https://inversepath.com/usbarmory) is an open source hardware design with an 800 Mhz ARM processor. It is a pocket-size 190 computer. When inserted into a laptop, it identifies itself as a USB network interface, basically adding another network 191 to your computer. Over this new network interface, you can SSH into the device. 192 193 Running Clef off a USB armory means that you can use the armory as a very versatile offline computer, which only 194 ever connects to a local network between your computer and the device itself. 195 196 Needless to say, the while this model should be fairly secure against remote attacks, an attacker with physical access 197 to the USB Armory would trivially be able to extract the contents of the device filesystem. 198