Skip to content
This repository has been archived by the owner on Sep 26, 2022. It is now read-only.

Add teos cli auth #262

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

orbitalturtle
Copy link
Collaborator

Tackles #230. Sets up a secure channel with TLS. (Generates a certificate for doing so.) And sends a user's provided username and password over the connection for verification.

@orbitalturtle orbitalturtle requested a review from sr-gi December 15, 2020 01:19
@sr-gi
Copy link
Member

sr-gi commented Dec 16, 2020

Nice! Will give it a first pass this weekend.

Copy link
Member

@sr-gi sr-gi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass. Haven't checked tests yet.

Tests are failing on circle-ci. Looks like a missing dependency(grpcio-testing)

test/teos/unit/cli/test_teos_cli.py:5: in <module>
    from grpc_testing import channel, strict_fake_time
E   ModuleNotFoundError: No module named 'grpc_testing'

Docs will need to be updated to cover the following:

  • How to add your own CERT in case you have it
  • Where to place the tower CERT in a remote CLI setup
  • How to re-generate the CERT for renewal (once added)

I also think the defaults for rpc user and password should be blank (if possible) and the tower should raise a warning if they are not set. Moreover, the tower should refuse to run if the user/pass are blank and the RPC host is not localhost.

@@ -192,44 +199,44 @@ def generate_key():
return PrivateKey()

@staticmethod
def save_key_file(key, name, data_dir):
def save_crypto_file(crypto_data, name, data_dir):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could call this save_bytes_file or save_file_bytes, given it has no actually cryptographic restriction.

with open(os.path.join(data_dir, "{}.der".format(name)), "wb") as der_out:
der_out.write(key)
with open(os.path.join(data_dir, "{}".format(name)), "wb") as crypto_out:
crypto_out.write(crypto_data)

@staticmethod
def load_key_file(file_path):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same applies to load_key_file, since currently the return messages make no sense for a certificate.

I think generalizing the messages and updating the name would do.

e.g.

"Key file path was expected, {} received" -> File path was expected, {} received"



@staticmethod
def generate_cert_key():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really debating between using openssl to generate the cert or do it with code. Given the code addition is rather small, I don't think it a big deal though.

However, I'd greatly encourage to use ECDSA instead of RSA. Furthermore, we are currently using DER for the rest of the keys, so I think we should also use DER for consistency here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, sounds good, I'll change to ECDSA. The reason I used PEM is because that's the format GRPC accepts. Sound okay for me to save the key/certificate as DER, and then just convert to PEM when we need to use them in GRPC?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I guess you can actually create Key and Cert objects with cryptography and the just call the pem / serialize_pem / whatever method gets the pem (I cannot recall atm) when passing the data to grpc.ssl_server_credentials.

If it ends up being too complicated it won't be worth it, so feel free to weight it and decide whatever you see fits best.

pk = sk.public_key()

subject = issuer = x509.Name([
x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"Teos watchtower"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Eye of Satoshi maybe? I've never liked teos that much tbh, but that the acronym we've got.


self.rpc_client = RPCClient(teos_rpc_host, teos_rpc_port)
rpc_cert = config.get("RPC_CERT")
rpc_user = config.get("RPC_USER")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rpc_user and rpc_password should be rewritable via command line params.

@@ -142,6 +142,17 @@ def __init__(self, config, sk, logger, logging_port):
bitcoind_feed_params,
)

if not os.path.exists(self.config.get("RPC_CERT_KEY")):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing this is here for the first bootstrap, but I think there's an uncovered edge case.

If the sk does not exists and the cert does exists, you will generate a new sk and load the old cert. That will not work.

I think you need to check that they both exist at the same time. There are basically 4 cases here:

  • Cert + SK -> Check that the SK and the CERT match. If not, you need to generate a new pair**
  • Cert + No SK -> The CERT is useless, you need to generate a new pair**
  • No cert + SK -> You need to generate a CERT, but I'm pretty sure the CERT that the admin has won't be valid anymore, since the dates won't match (care to double check this?), so probably you need to generate a new pair**
  • No CERT nor SK -> You need to generate a new pair**

** For the new pair generation, I think the best approach is not doing it straight-away. This is the same case as for when the CERT expires. A new RPC command (only available from localhost) needs to be added to re-create the CERT.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So basically here we should return an error regarding the data being invalid / corrupted / not found (whatever sounds good) and ask the user to regenerate the CERT.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants