Secure architecture for Rhasspy apps

I don’t see this happening securely in AppDaemon’s architecture, we need much more isolation for this. But you raise some good points that I want to discuss separately. Let me think about some possible solutions.

1 Like

If you really want full isolation, I think we should create a Docker container for each Rhasspy app. The advantage is that you can reuse Docker’s isolation features, for instance for network access, device access, access to directories on the host system, …

To limit access to specific MQTT topics, we can use access control lists in Mosquitto.

This way people can also easily check in a Docker Compose file and ACL file what resources the app needs. And an “app store” could expose this information in a more human-friendly way. Then we only need an “installer” that creates the Docker container and updates the ACL file.

A bonus feature is that this really works on an interface level: Rhasspy apps can be created in any programming language, as you only limit what they can do at the edge of the Docker container and the access to MQTT topics.

2 Likes

Yes individual docker containers was my thought aswell (or what I personally work with more podman pods mostly because they require no root and work with cgroups v2 which I use on Fedora)

That was the feature I was talking about. It would be relatively simple to automatically maintain this list from Rhasspy.

That was one of the things I did not 100% like about app daemon aswell. I personally write most my stuff in Python anyways, but I know there are many people that like to use e.g. javascript and since the container stuff is still existing tech (docker containers) we do not really have to reinvent much.

I heard some nice things about podman, can it be used on Raspbian too?

I think so but did not personally try yet. Basically it is mostly a 1:1 replacement of the stuff from docker with similar commands and works with the same containers. (There is nothing like docker-compose, but they work well with systemd services)

I really like it, but initially mainly started because docker still does not support cgroups v2 -> does not run on Fedora without switching back to v1 :rofl:

If you could do profile classification then it makes a lot of sense, but without voice identity the security are the apps you have installed and setup?

So… I did a small proof of concept :slight_smile:

Restricting network access for a Docker container is easy in docker-compose.yml: just create an internal bridge network:

networks:
  rhasspy-no-internet:
    driver: bridge
    internal: true

And then assign the container to this network:

  rhasspy-app-time:
    image: rhasspy-app-time
    container_name: rhasspy-app-time
    restart: always
    networks:
      - rhasspy-no-internet

Assign the mosquitto container to both this bridge network and the default network:

  mosquitto:                           
    image: eclipse-mosquitto               
    container_name: mosquitto
    [...]
    networks:
      - rhasspy-no-internet
      - default

Now the app in the Docker container can’t reach outside its own internal network (I checked with ping google.com, ping 8.8.8.8, ping rhasspy, ping 192.168.0.1), but it can reach the MQTT broker because the mosquitto container is in the same network.

This is a promising start :slight_smile: Now on to the Mosquitto ACLs…

5 Likes

The Mosquitto ACL to restrict access to specific MQTT messages also works. This goes roughly like this:

Add a password file and access control list to mosquitto.conf:

password_file /mosquitto/config/passwords
allow_anonymous false
acl_file /mosquitto/config/acl

Now for each Rhasspy app create a unique user and password, for instance with:

docker exec -ti mosquitto /usr/bin/mosquitto_passwd rhasspy-time-app

Then add the needed MQTT permissions to the ACL file, for instance:

user rhasspy-app-time
topic read hermes/intent/GetTime
topic write hermes/tts/say

And let the Rhasspy app authenticate to the MQTT broker with this username and password.

The result: this simple app that tells you the time is only able to subscribe to the hermes/intent/GetTime topic and only able to publish to the hermes/tts/say topic.

Of course this is just a toy example, but it proves the point that it’s quite doable to create isolated Rhasspy apps with Docker and Mosquitto ACLs. If @synesthesiam finds this approach interesting, I can create a repository to start working on a prototype that is fleshed out more. And then we need some sort of package format with conventions on how to specify the permissions an app needs.

When we go forward with this I would love to help with this aswell :wink:
When doing this I think something like your SnipsKit will be really helpful aswell. I suppose we can simply automatically generate docker containers from git repositories.

I find this an interesting discussion and really needed, but I am wondering if docker is the only way. For some odd reason I have a dislike of just pulling random images from the internet to run apps in that I rely on for the sake of making my environment more secure.

To be honest I think that apps need to be screened before they should be made officially available. If people want to run apps from other places, they are on there own. I do like the mqtt acl’s.

I agree that it would be best to screen applications you installe, but to be quite honest of how many apps that you installe e.g. on your phone is the source code open and you read it?
It is always a trust question, so e.g. for big open source projects I often tell myself that mostly someone else already checked the code, since I do not have the time to read a couple million lines of code.

It is the same with skills for rhasspy. Most of them are simple and I will read them (apparently this means e.g. I have to recheck the code base in front of each update). So when there is something like a official skill store project maintainers need to check it for each update without missing anything
(Apparently e.g. skills that have a library without a fixed Version somewhere in the dependency tree already has to be considered unsecure)
When using a more secure environment like docker it is a much smaller problem when there is an issue somewhere (this does not mean apps that are known to be vulnerable should be delivered, but I know it is easy to miss things)

Possibly web assembly with WASI could be an alternative (I did not really look into it lately) and not sure whether it is easily possible to limit e.g. interfaces it can access

@maxbachmann, I understand what you are saying in regards to trust. I do look at the permissions asked when I install apps on my phone and I have rejected a whole lot of them due to permissions or the origin of the maker, even though I was in need for the solution they provided. Try finding a good dual sim dailer :sob: .

In regards to docker, my problem is that I need to trust the original image maker as nobody creates their own image and I also need to trust the skill maker. To me docker does not provide me an additional security layer. For keeping skills separated it might have it’s function.

But aren’t these the same in this case? With this approach each Rhasspy app developer publishes their apps as Docker images. And you can always build the image yourself from the Dockerfile from the app’s source code repository.

I would say that in most cases this is the same person. Just like the docker images for rhasspy are mostly build on our ci. Apparently you need to trust the skill maker/image creator to some extend. However thats exactly where the docker containers come into play, since even when someone would create a malicious docker container he can only control the environment inside this container. So when we do not give the container network access and only access to a few mqtt topics, there is nothing it can do no matter how cracy it goes in there. And Rhasspy could provide you with informations which interfaces a skill wants to use before you install it, since either the skill provides this informations, or it does not get the interface unblocked. This way just like with your apps on the phone it is up to you to decide whether an skill really needs access to specific interfaces. However when installing them natively you will often simply not know which interfaces the skill will use without reading the source code.

Apparently this is both the case for unofficial and official skills. When there are official skills apparently we need to keep track of them anyways. So it probably makes sence to create a repository like the one mycroft uses mycroft-skills that simply includes them as submodules. This way skills are read when they are added and for updates it still requires a pull request to update the submodule sha, so the changes can be reviewed. Apparently not only because of the potential for malicious code, but e.g. to improve code quality and skill functionality and find potential bugs aswell, since we have quite a few people that have experience with skill development in this community :wink:
I guess for official skills it would make sence to simply build them on rhasspy’s ci aswell, so users know that any skill installed from e.g. rhasspy/skill-* is an official one. Beside this a central repository for all official skills can be used to automatically generate some kind of skill store where users can inform themselves about available skills like e.g. skill store mycroft. Since a official skill store is mostly a list of skills that work on a system and meet certain quality standards, the list will grow over time. So here docker still helps, since maintainers apparently need to make sure the skills do no unwanted things. These unwanted things do not only include malicious behaviour, but even more other things like unexpected crashes. E.g. a skill might have a memory leak and will therefore need a lot of memory over time. When using docker it is super simple to restrict the memory of each container and when it exceeds this memory limit it can restart the container and log an error about it (since it probably makes sence to inform the maintainers about this issue). Same when the skill segfaults for some reason.

Don’t you think that creating a Container for each skill uses much more memory and space then needed? There should at least be a option to bundle skills or have certified ones in a combined way.

I think this would have to be tested. Especially when working with similar base images for the docker containers you have similar shared libraries that should still only be loaded once. So I suppose the memory overhead should not be really big. Maybe I am just expecting a smaller amount of skills than what people actually use ^^

I suppose e.g. skills that do not even need Ethernet could always be put into a common container (as long as they use the same programming language). As a disadvantage this would require the container to be build in the device (so Installation would be slower). I guess when there is a way to tell it to bundle skills it is up to the user to decide which he wants to bundle.

Did anyone here test how much more memory is required when running a lot of containers with a single Python script vs one with many Python script?

Edit: I did just start up a couple of containers with python:slim-buster and measured their memory usage with docker stats.
Each of the containers required around 5.2 mb memory when opening the python shell in there.
And 1.5 mb when only opening bash in there.

8 posts were split to a new topic: No need for Rhasspy specific apps in terms of skills

Just to prove this point, this is the Dockerfile I whipped up for my proof of concept app:

FROM python:3.8.2-slim-buster
RUN pip3 install paho-mqtt 
RUN mkdir /app
WORKDIR /app

RUN groupadd -r rhasspy-app && useradd -r -g rhasspy-app rhasspy-app
RUN chown -R rhasspy-app:rhasspy-app /app

USER rhasspy-app

COPY time.py /app

CMD python3 /app/time.py

This is easy to automatically generate for any Rhasspy app/skill.

1 Like

The title of this topic is “Secure architecture for Rhasspy apps”. I have split your discussion about the need for Rhasspy apps to another forum post. This is not censorship, I did the same way with my fellow Rhasspy contributor @maxbachmann and this is actually how this post started, split from another topic to keep the discussion there clear.

5 Likes