- devise login
- react + apollo frontend
- graphql API, because state management in react is easier that way
- synchronous grpc or rest call. asynchronous call in fiber would be nice, but then we would need to have a push to the client
- grpc go greeting service. responds with Hello, + Name. The name is stored in the JWT
- alternatively there is a sinatra http server for the greeter in lib/api_server, you can toggle them in the Procfile. The backend will automatically fallback to rest when the grpc server is not found
- XSS: The message from the greeting service (even though this is not necessary) as well as the users name are sanitized
- self.new(h(message))
- self.name = sanitize(self.name)
- In theory sanitizing either one of these two would be enough, but since we pass the name to the client as well, we should do both
- JWT had a security bug where specifying the algo none would cause it to accept bad tokens, ruby doesn’t allow that
- I’m use HS256 default JWT tokens with shared keys.
- For more security we can rotate the shared keys and store them in Vault rather than config files
- There’s no TLS between the services, so someone could MITM the go greeting service
- cypress deps are insecure, but cypress is added to pkg.json for convenience of this example
- ansible deployment, secrets should be encrypted with ansible-vault
- the database password should not be stored in the default database.yml
- fail2ban for web and ssh is always a good idea
- The applications run as www-data but have too many privileges right now
Rotate shared secret, and distribute it with vault
- Either there is a pub key store somewhere
- Or apps are deployed with each others pub keys - this is an issue
Cause I want to know when you check out the page
This application requires:
- Ruby 2.4.2
- Rails 5.2.0
Learn more about [Installing Rails](http://railsapps.github.io/installing-rails.html).
- Go
- Node.js + npm (I guess this is a security issue all by itself)
We need to make sure the go grpc tools are available. And the ruby and go protobuf services are generated.
./prep.sh
./gen.sh # this will also set the correct GOPATH and build the greeter
(cd frontend ; yarn install)
(cd backend ; bundle install)Launching the services happens through foreman or docker.
cd backend
bundle exec rake db:create
bundle exec rake db:migrate
bundle exec rake db:seed
bundle exec foreman start(cd backend ; bundle exe rake spec)
There is a simple cypress e2e test in /frontend/cypress/integration/simple_spec.js
It checks for successful login.
(cd frontend ; npm install cypress; cypress ) # javascript e2e testshaproxy_frontends:
- name: https-in
mode: http
options:
- httplog
bind:
- '127.0.0.1:19443 ssl crt {{ certbot_dest_bundle }}'
acl:
- name: letsencrypt-acl
condition: path_beg /.well-known/acme-challenge/
- name: host_demo3
condition: hdr(host) -i demo3.xxx.com
use_backend:
- name: demo3_cluster
condition: if host_demo3
haproxy_backends:
- name: demo3_cluster
balance: leastconn
options:
- forwardfor
servers:
- name: node1
ip: x.x.x.x
port: 80configured automatically with ansible
- [X] set static shared key
- [X] create ruby greeter client
- [X] add JWT to go server
- [X] add expiration on JWT token
- [X] javascript e2e testing
- [o] ansible deployment
- [X] deploy to my server
- [X] fix ssl
- [ ] version the API
- [ ] stub faraday client in rails model
- [ ] fix the go mock
- [ ] add some ruby specs
- [ ] write test for greeting model
- [ ] setup fail2ban
- [ ] add docker compose
- [ ] make sure client properly cleans up token if it expires earlier or was invalidated
- [ ] Move const config from greeter_server to config files
- [ ] add TLS for service communication
- [ ] add openid_connect and auth proxy
- [ ] add something like linkerd for service communication