-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Aryeh/rpc-auth #36
Aryeh/rpc-auth #36
Conversation
Run `k create cm rpc-auth-config -n tqtezos1 --from-file rpc-auth/server/ --dry-run -o yaml | k apply -f -` to update the config map which will then contain the python script. Sometimes if you make updates locally to the file and run the above command, the pod will restart the server bec it's in debug mode. Most of the times it doesn't and it is unclear why.
rpc-auth/server/backend.yaml
Outdated
- "redis-cli -h $(hostname) ping" | ||
initialDelaySeconds: 5 | ||
periodSeconds: 3 | ||
# resources: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k8s noob question: at what point in time do we configure resources for all of our different infrastructure objects? How do we determine what the resources should be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's important to set resources once we are in production and have metrics collection in place. The main benefit is to have sensible autoscaling behaviour. In a minikube context it matters less since there is only one node anyway.
rpc-auth/server/index.py
Outdated
return False | ||
|
||
|
||
## Need a proper server for production |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to configure a proper server for production
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uwsgi!
2e92b44
to
14b7034
Compare
rpc-auth/server/index.py
Outdated
import requests | ||
|
||
TEZOS_CHAIN_ID = os.getenv("TEST_CHAIN_ID") | ||
TEZOS_RPC = f"{os.getenv('TEZOS_RPC')}:{os.getenv('TEZOS_RPC_PORT')}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TEZOS_RPC should be full endpoint, including scheme; as would be accepted by tezos-client's --endpoint paramemter in tezos 8.0; code below has `http hardcoded, which is problematic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see generate_secret_url actually uses request.url_root... I'm not sure how Flask application would know it's public url (must be explicit configuration?), but this assumes that this service would be doing the proxying of actual requests, which it shouldn't
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think at this point the Flask app needs to know its public url. Whatever host the client requests from in order to get a secret url in the first place is the host of the Flask app. They couldn't talk to our app without knowing the host's address. Then we can just use that host as the host of the secret url returned to the client.
rpc-auth/server/index.py
Outdated
|
||
@app.route("/tezos-node-rpc/<access_token>/<path:rpc_endpoint>", | ||
methods=["GET", "POST", "PATCH", "DELETE", "PUT"]) | ||
def rpc_passthrough(access_token, rpc_endpoint): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this web service should NOT take on proxying requests; correctly proxying all requests is not that simple; this naive implementation is already not correct even for simplest GETs (it doesn't pass along any headers); instead this service should be used together with nginx's auth_request (https://nginx.org/en/docs/http/ngx_http_auth_request_module.html)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now using nginx auth-url annotations to handle the auth subrequest
rpc-auth/server/index.py
Outdated
|
||
|
||
def verify_chain_id(chain_id): | ||
global TEZOS_CHAIN_ID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for global
here; would be even better if getting chain id were a function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intent here is that the server should not have to fetch the chain id on every request that a client makes. I set the CHAIN_ID var as a global variable at the top of the file so that it is kept in memory the whole time the server is alive. Only on the first request to the server will we go and fetch the chain id. I do have a get chain id function that is called a few lines below and is defined under this function.
Without setting global TEZOS_CHAIN_ID
i get a local var referenced before assignment error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without setting global TEZOS_CHAIN_ID i get a local var referenced before assignment error.
only because you try to assign it; caching function (e.g. using https://docs.python.org/3/library/functools.html#functools.cache) would provide a cleaner implementation (less global mutable state)
rpc-auth/server/index.py
Outdated
|
||
|
||
def create_nonce(): | ||
return str(uuid4().hex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to wrap in str()
rpc-auth/server/index.py
Outdated
|
||
|
||
def generate_secret_url(public_key): | ||
access_token = str(uuid4()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this gives the same format as create_nonce() but spelled differently, would be nice to be consistent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove the create_nonce() func as I don't think it is necessary. create_nonce() right now returns a uuid in hex format as that is required for the tezos-client while here it is plain uuid (cd470ace-264f-418b-95a2-4202bd8956dc). Not sure what you mean by "spelled differently". Would like this function to generate an access token in hex format as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the result is exactly the same as far as I can tell - hex string without dashes
❯ python
Python 3.8.6 (default, Oct 8 2020, 14:07:53)
[Clang 11.0.0 (clang-1100.0.33.17)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import uuid
>>> uuid.uuid4()
UUID('b7e0552e-6de4-4d5b-965e-48b9970f52db')
>>> uuid.uuid4().hex
'4f5359ef73f74663897ee9e903be51bc'
>>> str(uuid.uuid4().hex)
'a4d43e241bd640d08098f46fa8dcdab8'
>>> uuid.uuid4().hex
'7259e167589946659a5f0288f32c2d53'
>>>
rpc-auth/server/index.py
Outdated
|
||
|
||
@app.route("/vending-machine") | ||
def get_tezos_rpc_url(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should only accept POST method and be called "generate" rather than "get" since it is meant to have side-effects (generating new secret url every time)
rpc-auth/server/index.py
Outdated
|
||
def generate_secret_url(public_key): | ||
access_token = str(uuid4()) | ||
redis.set(create_redis_access_token_key(access_token), public_key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably be associated with tz address (pkh) rather than full public key since tz address is the common way of identifying tezos accounts
should probably also add access token to list associated with tz address (along with timestamp) so that we can inspect and, if need be, revoke or expire access codes for a given tz addres
rpc-auth/server/index.py
Outdated
return False | ||
|
||
|
||
## Need a proper server for production |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uwsgi!
rpc-auth/server/index.py
Outdated
|
||
def get_chain_id(): | ||
response = requests.get( | ||
urljoin(f"http://{TEZOS_RPC}", "chains/main/chain_id")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This web service in all likelihood may be able to access a Tezos RPC service by it's internal IP, while secret URL generated for the client will use public host/port - so not the same.
Node was listening also on ipv6 loopback when using "localhost". Not sure if this matters but for backwards consistency I changed it.
Taquito and Pytezos both work. const { TezosToolkit } = require("@taquito/taquito")
const tezos = new TezosToolkit(
"http://192.168.64.52/tezos-node-rpc/300c4ae403f343d49595076ce7bd97da"
)
tezos.rpc.getChainId().then(console.log)
// NetXvmLTRGRTusY from pytezos import rpc
rpcNode = rpc.node.RpcNode("http://192.168.64.52/tezos-node-rpc/300c4ae403f343d49595076ce7bd97da")
print(rpcNode.get("chains/main/chain_id"))
# NetXvmLTRGRTusY |
docker/rpc-auth/Dockerfile
Outdated
|
||
COPY --chown=appuser:appuser ./server/index.py . | ||
|
||
ARG FLASK_ENV=development |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prod is probably a better default
tqchain/mkchain.py
Outdated
@@ -319,6 +324,7 @@ def main(): | |||
"bootstrap_timestamp": datetime.utcnow() | |||
.replace(tzinfo=timezone.utc) | |||
.isoformat(), | |||
"rpc_auth": False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it is needed here. argparse will set it to false unless the user passes the arg.
--processes 1 \ | ||
--wsgi-file index.py \ | ||
--worker-reload-mercy 0 \ | ||
$(if [ "${FLASK_ENV}" = "development" ] ; then echo "--touch-reload index.py" ; else : ; fi) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that useful considering that devspace will rebuild and restart the container when something changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolasochem looks like devspace is set up to sync files for rpc-auth rather than rebuild image, so this makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is true
- Client can then make RPC requests: | ||
- `curl http://192.168.64.51/tezos-node-rpc/ffff3eb3d7dd4f6bbff3f2fd096722ae/chains/main/chain_id` | ||
- Bug in tezos client v8, so as of version `tezos/tezos:master_08d3405e_20201113152010`: | ||
- `tezos-client --endpoint http://192.168.64.51/tezos-node-rpc/ffff3eb3d7dd4f6bbff3f2fd096722ae/ rpc get chains/main/chain_id` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add a paragraph in DEVELOPMENT.md explaining how to spin up rpc-auth on minikube with devspace.
devspace.yaml
Outdated
docker: | ||
options: | ||
buildArgs: | ||
FLASK_ENV: ${FLASK_ENV} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this variable also needs to be declared in vars:
section below with source: env
and a default value otherwise devspace build
prompts for the value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolasochem I just tried with no prompt:
❯ echo $FLASK_ENV
❯ devspace build --skip-push -b
[done] √ Done building image tezos-rpc-auth:qchX3Uf (rpc-auth)
[done] √ Done building image tezos-zerotier:KkAWwY3 (zerotier)
[done] √ Successfully built 2 images
How can I reproduce?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolasochem yes, removing .devspace prompted me. thanks
tqchain/deployment/rpc-auth.yaml
Outdated
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: rpc-auth-service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just call it rpc-auth
?
@@ -0,0 +1,167 @@ | |||
import os |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
putting rpc-auth under docker
directory makes no sense to me; rpc-auth is a distinct component, just like mkchain. If we are not moving it out to a separate repo then rpc-auth and mkchain need to be sibling subdirs in the project, each with its own setup.py. Right now mkchain is "dominant" with its setup.py sitting in project root and rpc-auth is shoved under the rug in a weird place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a container centric view of the environment. mkchain does not belong here because it's not part of the cluster. It's a helper script to generate helm chart values.
See also: https://github.com/midl-dev/tezos-on-gke/tree/master/docker
One of the things I am planning is to migrate generateTezosConfig.py
and import_keys.sh
into init containers in the docker folder.
Perhaps mkchain could move to the scripts
folder that has been added in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mkchain is a software component, so is rpc-auth. They have their own packaging, dependencies, documentation, possible usage and deployment scenarios. I would really like to see component based structure here, perhaps even force it via putting them in separate repos (monorepo can work too, but not like this). Containers flow from that, not the other way around.
Maybe remove .devspace folder completely?
…On Fri, Nov 20, 2020, 9:41 AM Aryeh Harris ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In devspace.yaml
<#36 (comment)>:
> images:
zerotier:
image: tezos-zerotier
dockerfile: ./docker/zerotier/Dockerfile
context: ./docker/zerotier
+ rpc-auth:
+ image: rpc-auth
+ dockerfile: ./docker/rpc-auth/Dockerfile
+ context: ./docker/rpc-auth
+ build:
+ docker:
+ options:
+ buildArgs:
+ FLASK_ENV: ${FLASK_ENV}
@nicolasochem <https://github.com/nicolasochem> I just tried with no
prompt:
❯ echo $FLASK_ENV
❯ devspace build --skip-push -b
[done] √ Done building image tezos-rpc-auth:qchX3Uf (rpc-auth)
[done] √ Done building image tezos-zerotier:KkAWwY3 (zerotier)
[done] √ Successfully built 2 images
How can I reproduce?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#36 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAWXCY3U7DU6QARVFAZ4CTSQ2S53ANCNFSM4TEGEQNA>
.
|
3c23443
to
3ca2c86
Compare
mkchain generate-constants....
devspace use namespace tqtezos
cd ./docker/rpc-auth
devspace dev --var=CHAIN_NAME="$CHAIN_NAME"
--var=CHAIN_ARGS="--docker-image=tezos/tezos:v8-release ..."
)The above will build (if not already built) the python and zerotier docker images, and apply the yaml for mkchain and rpc auth server. It also enables the minikube nginx addon so that the rpc-auth ingress can work.
Thoughts/Comments on first iteration of this auth mechanism: