Thursday, 9 September 2021

etcd - Today I learned ...

I've been tinkering with the most recent version of etcd namely 3.5.0 recently, having built it from their GitHub project.

My initial and main requirement was to test etcd with SSL/TLS, specifically both server-side X509 certificate-based encryption ( to validate endpoint integrity and on-the-wire data encryption ) AND client-side certificate-based authentication ( to ensure that only authenticated clients could access the etcd service ).

Having got this done and dusted, albeit with a self-signed certificate process, with a locally-created Certificate Authority (CA) being used to create the keys and certificates being presented: -

(a) by the etcd server to its clients

(b) the client consuming etcd, both via its REST APIs, being consumed by curl and also the native etcdctl utility.

Now I'm looking at the REST API in more depth, having previously only tested the /version endpoint: -

curl --silent --cacert /root/ssl/ca-cert.pem --cert /root/ssl/client-cert.pem --key /root/ssl/client-key.pem https://localhost:2379/version | jq

{
  "etcdserver": "3.5.0",
  "etcdcluster": "3.5.0"
}

I then wanted to try sending data to, and receiving data from, etcd again using its REST APIs, recognising that the purpose of etcd is: -

etcd is a strongly consistent, distributed key-value store that provides a reliable way to store data that needs to be accessed by a distributed system or cluster of machines.

Source: https://etcd.io/

Thankfully, the etcd documentation does cover this nicely: -

Why gRPC gateway

Interestingly, this uses the POST HTTP method for almost all of the operations, both PUT and GET, which was new to me ...

The documentation does cover this: -

Put and get keys 

Watch keys

etc.

Interestingly, we have this: -

The gateway accepts a JSON mapping for etcd’s protocol buffer message definitions. Note that key and value fields are defined as byte arrays and therefore must be base64 encoded in JSON. The following examples use curl, but any HTTP/JSON client should work all the same.

Source: Using gRPC gateway 

Using a test JSON document: -

cat dave.json

{
"key":"012345",
"value": {
"name":"Dave Hay",
"id":"davidhay1969"
}
}

I need to encode the key and the value into base64; the Q&D way to do this is using jq and base64

cat dave.json | jq -r .key | base64

MDEyMzQ1Cg==

cat dave.json | jq -r .value | base64

ewogICJuYW1lIjogIkRhdmUgSGF5IiwKICAiaWQiOiAiZGF2ZWhheTE5NjkiCn0K

and then insert those into a new JSON document: -

cat dave_b64.json

{
"key":"MDEyMzQ1Cg==",
"value": "ewogICJuYW1lIjogIkRhdmUgSGF5IiwKICAiaWQiOiAiZGF2ZWhheTE5NjkiCn0K"
}

We can then put that into etcd again using the REST API: -

curl -X POST --silent --cacert /root/ssl/ca-cert.pem --cert /root/ssl/client-cert.pem --key /root/ssl/client-key.pem https://localhost:2379/v3/kv/put -d @dave_b64.json | jq

{
  "header": {
    "cluster_id": "14841639068965178418",
    "member_id": "10276657743932975437",
    "revision": "8",
    "raft_term": "2"
  }
}

and then query etcd to get it back out again ...

Now, for some reason, etcd uses the range endpoint rather than, say, get but that's fine ....

curl -X POST --silent --cacert /root/ssl/ca-cert.pem --cert /root/ssl/client-cert.pem --key /root/ssl/client-key.pem https://localhost:2379/v3/kv/range -d '{"key":"MDEyMzQ1Cg=="}' | jq

{
  "header": {
    "cluster_id": "14841639068965178418",
    "member_id": "10276657743932975437",
    "revision": "8",
    "raft_term": "2"
  },
  "kvs": [
    {
      "key": "MDEyMzQ1Cg==",
      "create_revision": "7",
      "mod_revision": "8",
      "version": "2",
      "value": "ewogICJuYW1lIjogIkRhdmUgSGF5IiwKICAiaWQiOiAiZGF2ZWhheTE5NjkiCn0K"
    }
  ],
  "count": "1"
}

Note that we get back the base64 encrypted value field: -

      "value": "ewogICJuYW1lIjogIkRhdmUgSGF5IiwKICAiaWQiOiAiZGF2ZWhheTE5NjkiCn0K"


We can quite easily decode this manually: -

echo "ewogICJuYW1lIjogIkRhdmUgSGF5IiwKICAiaWQiOiAiZGF2ZWhheTE5NjkiCn0K" | base64 -d

{
  "name": "Dave Hay",
  "id": "davehay1969"
}

or decode it on the fly: -

curl -X POST --silent --cacert /root/ssl/ca-cert.pem --cert /root/ssl/client-cert.pem --key /root/ssl/client-key.pem https://localhost:2379/v3/kv/range -d '{"key":"MDEyMzQ1Cg=="}' | jq -r .kvs[].value | base64 -d

{
  "name": "Dave Hay",
  "id": "davehay1969"
}

I'm sure I can script up a process to create the JSON document containing Base64-coded data without too much problem ....

TL;DR; writing to / reading from etcd feels very achievable, recognising that there's a bit of a learning curve to (a) understand the REST API and (b) handle the Base64 encoding / decoding process ....


Tuesday, 7 September 2021

openssl - Get your subject right

I'm tinkering with OpenSSL to create a Certificate Authority, server keys/certificates and client keys/certificates and keys.

Having done all of this, I was then looking to verify the server's certificate - server-cert.pem - again using openssl as follows: -

openssl verify server-cert.pem 

C = GB, O = IBM, CN = david_hay.uk.ibm.com
error 18 at 0 depth lookup: self signed certificate
error server-cert.pem: verification failed

Wait, what now ?

Thankfully, this came to my rescue: -

I think you missed this part of the instructions:

Whatever method you use to generate the certificate and key files, the Common Name value used for the server and client certificates/keys must each differ from the Common Name value used for the CA certificate. Otherwise, the certificate and key files will not work for servers compiled using OpenSSL.

When OpenSSL prompts you for the Common Name for each certificate, use different names.


When I created the server's certificate: -

openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-req.pem -subj '/C=GB/O=IBM/CN=david_hay@uk.ibm.com

I'd used the same Subject as I used for the Certificate Authority (CA) e.g.

openssl req -new -x509 -nodes -days 365 -key ca-key.pem -out ca-cert.pem -subj '/C=GB/O=IBM/CN=david_hay@uk.ibm.com

which is a pretty bad idea.

Once I did it properly: -

openssl req -new -x509 -nodes -days 365 -key ca-key.pem -out ca-cert.pem -subj '/C=GB/O=IBM/CN=etcd_ca'

for the CA and: -

openssl req -newkey rsa:2048 -nodes -keyout server-key.pem -out server-req.pem -subj '/C=GB/O=IBM/CN=etcd_server'

for the server, all was well.

For reference, this is from where I started wrt using openSSL in this context: -

Thursday, 2 September 2021

GitHub Copilot for VSCode Might Make Coding Easier

Saw this over on @podfeet's blog: -

GitHub Copilot for VSCode Might Make Coding Easier

For reference, @podfeet, aka Allison Sheridan, is the host of a number of podcasts, including NosillaCast, Programming by Stealth and Taming the Terminal: -

Podfeet Podcasts

along with Bart Busschots of Let's Talk Apple etc.

I recommend a read of the GitHub Copilot article, and also a listen to / follow of Allison and Bart, and their respective ( and respectable ) podcasts.


Kata Containers - spell checking the docs

I'm working on a change to some of the Kata Containers documentation, and hadn't - until today - realised that the project has a rather neat Spell Check tool that runs against documentation e.g. that written in Markdown.

The tool - kata-spell-check.sh - has its own README and relies upon a set of dictionaries, leveraging the hunspel and pandoc projects.

To use/update this on my Ubuntu box, I needed to install those two projects: -

apt-get update && apt-get install -y hunspell

apt-get update && apt-get install -y pandoc

and then clone the Kata test project: -

git clone git@github.com:kata-containers/tests.git

I was then able to update the dictionary: -

vi ~/tests/cmd/check-spelling/data/main.txt

to add in the to-be-included words, and then run the appropriate command to have kata-spell-check.sh update its own internal dictionary: -

cd ~/tests/cmd/check-spelling

./kata-spell-check.sh make-dict

and then run the tool itself: -

./kata-spell-check.sh check ~/foobar.md 

INFO: Spell checking file '/root/foobar.md'

INFO: Spell check successful for file: '/root/foobar.md'

This against the world's most simple Markdown file: -

# Context

## Introduction

This is some text.
This is an error - `error message`

but you get the idea :-)

Wednesday, 1 September 2021

Apple TV - subtitles on

In the context of a previous post: -

Apple Remote - tell the telly to turn the heck off !

I had a similar requirement - to have Apple TV show subtitles whilst watching Discovery+

The answer ? Simples !

Just press the mic button: -




and ask "Please turn subtitles on"

It worked!

And, perhaps unsurprisingly, the reverse also worked - "Please turn subtitles off"

I ❤️ my Apple TV 

Reminder - Apple Time Machine - where are your logs ?

Want to see what Time Machine is doing ?

If so, run the following Terminal command: -

printf '\e[3J' && log show --predicate 'subsystem == "com.apple.TimeMachine"' --info --last 6h | grep -F 'eMac' | grep -Fv 'etat' | awk -F']' '{print substr($0,1,19), $NF}' 

which is, in part, parsing the output from the log show command.

Which is nice 🌞

Forgot to include my source for the above: -

Note to self - Firefox and local connections

 Whilst trying to hit my NAS from Firefox on my Mac, I kept seeing errors such as:- Unable to connect Firefox can’t establish a connection t...