Some months back I was faced with an interesting challenge in Microsoft Teams. How do we prevent chats for users that have access to an external tenant? The background here is that certain industries like mine require you to capture and archive electronic communications. Depending on how you interpret the requirement this could include chats taking place in a tenant other than your own. An administrator naturally has zero access to the data in a tenant other than their own. You can use tenant restrictions to prevent a user (who you have some network or proxy control over) from accessing a tenant other than your own, but there are cases where a user needs this access for external collaboration. The challenge here was finding a way to prevent certain actions while working in another tenant… and so came TeamsFirewall.
I started analyzing Teams traffic in my free time and got a feel for how it works. I quickly realized that I could approach the issue with a scriptable proxy server that supported HTTPS. I chose mitmproxy for this task. In the first iteration of the product I broke traffic down to actions (like sending a message or deleting a message) and location (internal tenant or external tenant). After I had that working I wanted to expand the functionality to control actions based on not only location, but on other things like conversation type and participants. After more development I came up with a process that learns the environment by looking at action -> conversation -> participants. The system caches API tokens from the users it supervises to make requests on their behalf in order to learn what it does not know about the environment. The product does not need any credentials or direct access to a tenant to function. This data is then saved in the cache database (teamsfirewall_cache.db). The cache is used for lookups so that faster decisions can be made on the fly. Cache lifetime of both the user table and the conversation table can be configured via the config file.
The rule engine of the product allows for extremely granular rulesets. You can get as granular as saying user A cannot edit messages sent to user B or as broad as user A/B/C cannot communicate with anyone @companyA.com. I would like to note that M365 Information Barriers perform some basic ethical wall functions, but it does not have much granularity and does not address examples like the the one above with external tenants.
Some next steps are improving the scalability of the product and developing an easily deployable package. I am currently looking at adding an option to use a central database for the cache database and using Docker containers with a load balancer to add more workers. You can see some of this upcoming work in the TODO file within the project repository (below).
All development and documentation will be maintained at the TeamsFirewall GitHub here: https://github.com/markdepalma/TeamsFirewall. Please feel free to post issues/questions and contribute!
Pingback: TeamsFirewall – The open-source ethical firewall for Microsoft Teams – 365 admin service
I am pretty sure I’ve figured out how to add an option to use a central database for the cache database and using Docker containers with a load balancer to add more workers. The key lies in between using the right access point when utilizing the caches.
Yes, please share. My initial idea was just to add code to allow for MySQL and/or MS SQL to be used (in addition to the SQLite database). All the Docker containers could use the one database and share cache data. I’ve still been thinking through the load balancing piece. load balancing itself is easy but I also want to be able to provide the original client IP to the core process in order to use the client IP in XFF headers.
load balancing would be a good idea provided you can keep the original client IP to the core process in order to use the client IP in XFF headers , using proxy control and certain limitations in the parameters would help but I’m not sure if it would be a seamless integration.
I’m evaluating different options. Once the load balancing is settled everything else is fairly simple. If you come up with an idea please post here or in the GitHub. Really looking for community involvement!