Redis ios client using websocket in secure way - ios

I am currently communicating with my Redis instance from my iOS client using a websocket. I specify the host address and the listening port and execute some Redis Commands from my IOS client directly.
The reason I am doing that because I am doing real live geolocation tracking and executing these commands from my backend which is in php will result in latency.
I am afraid that this is not the most secure way because if someone knows my host address and ports he will be able to access my Redis Instance.
My question is how can I communicate with my Redis Instance from my iOs client using a websocket but in a more secure way.

#Ahmed,
I read the answer provided by #ThatCampbellKid and the comments and understand your wish to have the iOS client communicate directly with the Redis server.
However, Redis was NOT designed for this approach. As indicated in the documentation (emphasis added):
Redis is designed to be accessed by trusted clients inside trusted environments.
The internet is not a trusted environment and the direct access allows Redis to be accessed by non-trusted clients.
The same documentation gives the following example (emphasis added):
In the common case of a single computer directly exposed to the internet, such as a virtualized Linux instance (Linode, EC2, ...), the Redis port should be firewalled to prevent access from the outside. Clients will still be able to access Redis using the loopback interface.
The correct approach would be to use a dynamic application to authenticate clients and bridge between clients and the Redis server.
You can use JWT (the nginx module suggested by #ThatCampbellKid), PHP, Ruby, node.js, Java, C or whatever you want - but you will need to use something.
I'm sorry to say this, but any other shortcut will expose your system to security risks.
EDIT:
Yes, you can still use WebSocket.
The difference is that this architecture is not secure:
Client <=(WebSockets)=> Redis
And this architecture is secure (if implemented correctly):
Client <=(WebSockets)=> Authentication Layer <=(TCP)=> Redis

There are a couple ways of doing it, depending on how your project is set up. You could add an NGINX loadbalancer in front of your php/redis containers that accepts JSON Web Tokens for authentication.
https://www.nginx.com/blog/authentication-content-based-routing-jwts-nginx-plus/
Redis has the ability to do authentication as well, but isn't considered best practices it looks like, but you can find more information about it here also:
https://redis.io/commands/auth

As you said you are already running Nginx then have a look at the Nchan websockets module
Your Nginx install can then serve websocket connections directly and it has support for several methods of client authentication as well as direct integration with redis

Related

How to expose a service from minikube to be able to access it from another device in the same network?

I've created a service inside minikube (expressjs API) running on my local machine,
so when I launch the service using minikube service wedeliverapi --url I can access it from my browser with localhost:port/api
But I also want to access that service from another device so I can use my API from a flutter mobile application. How can I achieve this goal?
Due to small amount of information and to clarify everything- I am posting a general Community wiki answer.
The solution to solve this problem was to use reverse proxy server. In this documentation is definiton what exactly is reverse proxy server .
A proxy server is a go‑between or intermediary server that forwards requests for content from multiple clients to different servers across the Internet. A reverse proxy server is a type of proxy server that typically sits behind the firewall in a private network and directs client requests to the appropriate backend server. A reverse proxy provides an additional level of abstraction and control to ensure the smooth flow of network traffic between clients and servers
Common uses for a reverse proxy server include:
Load balancing
Web acceleration
Security and anonymity
This is the guide where one can find basic configuration of a proxy server.
See also this article.

Serving dockerized microservices over HTTPS

I'm currently struggling with docker and SSL. Let me give you an overview on what I'm trying to do.
I built a microservice-based architecture which is composed by a react web application and some "backend" services written in python and exposed with gunicorn on docker containers. I need to serve it over SSL because of Auth0 which needs the https communication. So, I built the server, bought a domain and got the SSL certificate for the domain with let's encrypt.
Now, here are the troubles, since mi services communicates to each other with a docker network, say services-network. For this reason they refer each other with the url `service:port/example.
At the moment I'm able to successfully connect to my web app with https but whenever this tries to contact the "backend" services the connection is refused because of it came from a non-secure resource (I used http://service:port/endpoint).
I tried to use the let's encrypt certificate generated for the webapp but the communication is blocked with message requests.exceptions.SSLError: HTTPSConnectionPool(host='service', port=8081): Max retries exceeded with url: /endpoint (Caused by SSLError(CertificateError("hostname 'service' doesn't match 'domain.com'",),))
I understand that a possible workaround for this error is to make the services communicate each other without using the docker network but the external one. Anyway I think that is not a good practice and that the communication among containers needs to be done through the docker network.
Finally, my question is: which is the best way to make the containers communicate through https over the docker network?
I personally like to use nginx as a reverse proxy. You would configure it normally and set it to proxy_pass <dockerIp:port>.
Many people like to use traefik.io which has many features including Let's Encrypt integration.

Using traefik for docker internal traffic via websockets

I'm using docker in swarm mode for the services in my application and traefik to handle, well, the traffic. My goal is to make a separate service for each API section my application has (so for example requests on domain.com/api/foo_api go to the foo_api service and requests on domain.com/api/bar_api go to the bar_api service.
Now all this is pretty straightforward with traefik. However, I'm also using the API services with other internal services not related to the API. They use a websocket connection to the internal docker URL, so currently it's ws://api:api_port/ws. However, if I split up the API part I'd need something like ws://foo_api:foo_api_port/ws which obviously leaves the service only access to the foo_api, not every other one.
So my question is: Can I route this websocket traffic with traefik similiar to how I do it externally, but internally in the docker net?
Traefik is a north-south reverse proxy. Most people historically in traditional infrastructure would use NGINX or Apache to address inbound - good to see you using a more modern tool. What you are describing is an east-west pattern of communication inside your firewall behind traefik (assuming you control all ingress through traefik).
Have you considered using service discovery and registry capabilities with tools like Hashicorp Consul - https://consul.io?
The idea of having service discovery is so that your containers / services inside the swarm can be discovered and made available through the registry and referenced in proximation to each other by name without the pains of manual labor in building and maintaining complicated name-IP-lookups. Most understand this historically in a more persistent model behind DNS SRV which requires external query. Consul can still support that legacy reference integration as well.
This site might help you along: https://attx-project.github.io/Consul-for-Service-Discovery-on-Docker-Swarm.html
They appear to have addressed a similar case to yours. And the work is likely reusable with a few tweaks.

deploying Spring Boot Rest Service with https enabled, in kubernetes

I have developed a spring boot based REST API service and enabled https on it by using a self signed cert keystore (to test locally), and it works well.
server.ssl.key-store=classpath:certs/keystore.jks
server.ssl.key-store-password=keystore
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=tomcat
Now, I want to package a docker image and deploy this service in a kubernetes cluster. I know I can expose the service as a NodePort and access it externally.
What I want to know is, I doubt that my self signed cert generated in local machine will work when deployed in kubernetes cluster. I researched and found a couple of solutions using kubernetes ingress, kubernetes secrets, etc. I am confused as to what will be the best way to go about doing this, so that I can access my service running in kubernetes through https. What changes will I need to do to my REST API code?
UPDATED NOTE : Though I have used a self signed cert for testing purposes, I can obtain a CA signed cert from my company and use it for production. My question is more on the lines of, For a REST API service which already uses a SSL/TLS based connection, what are some of the better ways to deploy and access the cert in kubernetes cluster , eg: package in the application itself, use Secrets, or scrap the application's SSL configuration and use Ingres instead, etc. Hope my question makes sense :)
Thanks for any suggestions.
Well it depends on the way you want to expose your service. Basically you have either an ingress, an external load balancer (only in certain cloud evironments available) or a Service thats routed to a Port (either via NodePort or HostPort) as options.
Attention: Our K8S Cluster is self hosted so I have no reliable information about external load balancers in K8S and will therefore omit that option.
If you want to expose your service directly behind one of your domains on port 80 (e.g. https://app.myorg.org) you'll want to use ingress. But if you don't need that and you can live with a specific port the NodePort approach should do the trick (e.g. https://one.ofyourcluster.servers:30000/).
Let's assume you want to try the ingress approach than you need to add the certificates to the ingress definition in K8S instead of the spring boot application or you must additionally specify that the service is reachable via https itself in the ingress. The way to do it may differ from ingress controller to ingress controller.
For the NodePort/HostPort you just need to enable SSL in your application.
Despite that you also need a valid certificate e.g. issued by https://letsencrypt.org/
Actually for K8S there are some projects that can fetch you a letsencrypt certificate automatically if you to use ingresses. (e.g. https://github.com/jetstack/cert-manager/)

Rails app call APIs using proxy

I have subscribed to an API service which provides access based on static IP (For both Live and Testing).
Since my development area ISP doesn't provide a static IP, I have enabled API access to my staging machine IP, which is static. I installed squid and enabled/setup a proxy server in my staging server so that I can use it as a proxy and make calls to the API while i do development.
I am using Mac for my development and Networking>Proxy settings wont work for system wide( Terminal ). Due to this, I was using Trial versions of MacProxy, proxifier( proxy clients) and all was was working fine till trial expired. Are there any free alternatives to this for Mac?
I tried to setup proxy by creating ssh socks proxy and setting http_proxy="xxx". In terminal. When I check terminal IP post setting using curl ipecho.net/plain ; echo, it shows proper IPs but when I run local rails development server and tries to access the API, its rejecting call with invalid IP (it shows non proxied IP)
An free alternative that might solve your problem might be a project on github:
sshuttle (read me)
It forwards TCP and DNS requests a remote ssh server.
The most basic use of sshuttle looks like this:
./sshuttle -r username#sshserver 0.0.0.0/0 -vv
To tunnel all traffic you might do:
./sshuttle --dns -vr ssh_server 0/0
There are also helper functions available here, which can simpify some of the commands.
The system level proxy settings aren't used by ruby applications. Typically this is a code level option passed to the library you are using to make connections.
If you want Savon to use a proxy then you need to pass this to Savon when you create the client:
client = Savon.client(proxy: "http://example.org", ...)
If this call is being made inside a gem, then unless that gem already provides that option then you would need to fork it to add the option
The gem you mention seems to already implement this - it's configuration class has a proxy attribute that seems to be passed through to savon.

Resources