Authentication
Authentication mechanism is already implemented in all our official client libraries. If you are implementing a new client library for an unsupported language, or you are just curious how it works then this page will help you.
Each API Key consists of a pair of Key ID and Secret Key. A Key ID is always provided with each request to identify a caller. A Secret Key is used to sign that request. An account can have multiple API keys. Any key can be revoked if needed. In Cloud each key has an associated role (more on Authorization here).
Every API request should have the following gRPC headers:
evrblk-api-key-id- API Key IDevrblk-signature- A signature of a given requestevrblk-timestamp- A timestamp of a given request (Unix time in seconds)
A signature is calculated for a combination of:
- Timestamp
- Service name (i.e.
Moab) - Method name (i.e.
CreateQueue) - Protobuf serialized request body
Timestamps, service and method names are used to prevent Replay Attacks.
Each request should be timestamped within [now - 5 min; now + 5 min] interval to allow for some clock drift. Service
and method names help distinguish between similar payloads, for example GetQueue{queue_name: "my_queue"} and
DeleteQueue{queue_name: "my_queue"} have the same request body.
There are several supported authentication mechanisms that go by names: Alfa, and Bravo. They use different signing methods, vary in performance, and trust level. If new mechanisms appear in the future, or there is a need to fix something in existing ones, they will be created under new names and existing mechanisms will be kept untouched for backward compatibility.
Alfa
This is the recommended signing mechanism for enterprises and very paranoid users.
Alfa is based on prime256v1 (aka NIST P-256, aka secp256r1) cryptographic signature algorithm. Public and private
keys are PEM encoded and are generated by user. Only the public key is stored in the cloud. That means that user keys
cannot be compromised in an unlikely event of a security breach. That also means that Secret Key cannot be restored if
it has been lost.
Pseudocode on the client side:
timestamp_bytes = int64_to_bytes(timestamp) // 8 bytes big endian of Unix timestamp
request_bytes = proto_marshall(request) // binary proto representation of a request
data = timestamp_bytes + service_name + "." + method_name + request_bytes
signature = p256_sign(private_key, data)
Pseudocode on the server side:
timestamp_bytes = int64_to_bytes(timestamp) // 8 bytes big endian of Unix timestamp
request_bytes = proto_marshall(request) // binary proto representation of a request
data = timestamp_bytes + service_name + "." + method_name + request_bytes
result = p256_verify(public_key, data)
Alfa key can be generated with openssl:
# Generate ecdsa private key with explicit prime256v1 curve
$ openssl ecparam -name prime256v1 -genkey -out prime256v1-key.pem
# <private key output>
# From the private key, generate a public key
$ openssl ec -in prime256v1-key.pem -pubout -out prime256v1-pub.pem
Or it can be generated with evrblk CLI tool:
$ evrblk authn generate-alfa-key
Bravo
Bravo is based on a large random string as a secret. It is not sufficient for very paranoid users because the secret is stored in the cloud. Bravo signing mechanism is much faster and simpler than Alfa. Bravo keys are used in Everblack Console, a new short-lived Bravo API key is created on each user sign in, the secret is encrypted and stored in cookies. On every request Console decrypts the secret from cookies and uses it to call Everblack API.
Bravo secret is 512 random bytes encoded in Base64. The signature is sha256 of a timestamp, a request, and a hashed
secret (sha256 of a secret key and a date). Extra step of hashing the secret with a date allows safe caching on API
servers without leaking the real secret outside AuthN service boundaries.
Pseudocode on the client side:
timestamp_bytes = int64_to_bytes(timestamp) // 8 bytes big endian of Unix timestamp
request_bytes = proto_marshall(request) // binary proto representation of a request
date = dateOf(timestamp)
date_bytes = format(date) // date in "YYYY-MM-DD" format
hashed_secret = sha256(secret, date_bytes)
data = timestamp_bytes + service_name + "." + method_name + request_bytes
signature = hmac_sha256(hashed_secret, data)
Pseudocode on the server side:
timestamp_bytes = int64_to_bytes(timestamp) // 8 bytes big endian of Unix timestamp
request_bytes = proto_marshall(request) // binary proto representation of a request
date = dateOf(timestamp)
date_bytes = format(date) // date in "YYYY-MM-DD" format
hashed_secret = sha256(secret + date)
data = timestamp_bytes + service_name + "." + method_name + request_bytes
expected_signature = hmac_sha256(hashed_secret, data)
result = actual_signature == expected_signature
Bravo key can be generated with evrblk:
$ evrblk authn generate-bravo-key