 My name is Joe Conway, I work for a company called Crunchy Data. We specialize in Postgres and enterprises with a particular focus on secure environments. So I'm here to talk about MLS Postgres. What I'm going to do is start out at a kind of 50,000 foot level and hopefully help you understand what MLS is really all about and then dive down into a little bit more detail about the specific components and how the system needs to be set up. And then I'll go through some results, what it actually looks like in practice. So in terms of what is MLS, fortunately that text maybe, can you see that text in the back of the room? So multi-level security, and in particular what I'm talking about here is multi-level security as implemented by SCLINX. There's a notion of sensitivities, which are kind of levels of access. And they're labeled generically as S0 through S15. And you can actually define them for yourself to decide what that should mean to you. Military type context, this might be S0 is unclassified, S4 might be classified, S5 might be secret, S6 might be top secret, something like that. In another context, you could label it whatever you want. The notion is just from high to low. In addition to the sensitivities, you also get these categories, which you don't have to use, but you can use. And the idea of the categories is they further compartmentalize access. So this is how you would implement the notion of need to know. So if I've got a certain level here at S5, but I don't have this compartment C2, this category C2, then that means there's some information in that particular project that I don't have a need to know, even though I have the right level. So what would this maybe look like for a non-military use? If you think of these as access groups, and in this case, I've got management, employees, and external. And now if you go and expand that, these become individual projects at a company. So if I look at just that one square right there, this is both external and it's not associated with a specific project. So that would be something that would be truly public. That's information that you want to share with anyone. Whereas over here, I've got external access, but it's associated with a specific project. And so that might be information that you want to share with a customer or a partner. Now up into this cell here, I've got employee access for a specific project. So that might be the scrum team that's working on that project. And then finally, at this level, the management level in that project, that might be the product owner. So just the highest level, maybe that's financial information about the project that's not shared with everyone, something along those lines. From a practical use, the way this looks is, you might have a client that has access to all three levels. And you've got Postgres running with access to all three levels, data at all three levels. You have to, in some way, shape or form decide what level you want to connect at. And then use an appropriate network connection to make that. Because you want the data that's going over the wire to be constrained to the level that your network is supporting. So that can be done in at least a couple of ways that we've done. One of them, as I've written here as IPsec, you can actually tell IPsec that you wanna connect with a certain SCLinux range. And the packets all get labeled with that range. And so when the connection is made, that security level gets carried over through IPsec. The other way you can do it is you can have just multiple interfaces on your Postgres server, and you can set up something called NetLabel. NetLabel will take an unconfined, meaning a connection that doesn't have otherwise SCLinux labels on it. And based on the interface that you've connected to, it'll label it for you. So you can decide that if you want to constrain a particular subnet, 192.168.4.x is always gonna be my lowest level network. And 5.x might be my classified level. 6.x might be my secret level. So I confine the packets on the network to a particular level. But IPsec is a much more flexible way to do that. And then finally, once you make the actual connection from the client using Pseql or something else to Postgres, now the context within Postgres is gonna be restricted to that same level. So I know this might not all make complete sense to you right now. But I'm hoping that the picture is combined with what I'm gonna go through next. It'll start to come together for you. Now why not, what's the business case for this? Certainly in a government or a military kind of context, there is, they will literally have multiple sets of hardware sitting on the desk. So if you want to access data at a certain level, you have to sit down at this system. And if you want to access it at another level, you have to sit down at this system. So there's a great deal of desire to be able to do this sort of thing in the database in order to eliminate redundant hardware. Redundant hardware on the client, redundant hardware on the server side. But even if you're just separating out your data for this security-wise for your business, there's still a lot of problems in terms of redundancy in terms of duplicating of data that you want shared everywhere. In terms of being able to do reporting across all of the levels in a secure way. And in addition, again, I'll get to this in a few slides. But the difference between what we're doing here and kind of normal database security is that this is something called mandatory access control. It's controlled by the system and by policies on the system. And not by the person who's creating the object or creating the data. Which is a little different than in a normal database system where you have discretionary access control. Basically whoever creates the table decides who can see the table, for instance. And you could do this filtering through your application, but this way the database is providing the integrity for you, which is what we like to use databases for. And this whole system relies on something called RLS, which is nice, it's fairly transparent. And with some testing, I'll show you later that it performs really well. Any questions about all that before I move forward? Okay, so now talk about the major components of the solution. First one is row level security. It's a brand new feature in 9.5 that just came out. It's enabled on a per table basis. So you don't have to have every table using RLS. You can choose which tables you want. It's enforced with a policy. So on tables that have RLS, you're going to define a policy, one or more policies. And in those policies, you're going to use what's called a using expression or a with check expression. And basically the way that breaks down is the using expression is looking at the old row and deciding whether or not you get to see it. It's a filter. And the with check expression is looking at the new row and deciding whether or not you can actually commit that new row. And if you can't, it'll throw an error. So in terms of this is an example of row level security. It's not MLS specific, but I wanted to start you off with something that was just pure RLS so you can understand how it works. So anyway, how many people in the room have played with RLS at all? A few, okay. So in this case, I'm creating a user called Bob. A user called Alice, create this table that's got three fields in it. Importantly, the third one is called app user. I'm going to insert some dummy data into the table with the first row in the app user column, I'm labeling it Bob. And in the second row, I'm labeling it Alice. And then I'm going to alter the table to enable row level security. And I'm going to create a policy that says using app user equals current user. And now I have to grant select on that table to public. So now when I go to use this table, if I'm still super user, I'm actually going to see both rows because RLS doesn't apply to super user. But when I set myself up, basically log in as Bob, you notice Bob only sees Bob's row. And if you log in as Alice, Alice only sees Alice's row. So that's in a nutshell what RLS will do for you. Fairly simplified, we'll see more examples later of this in terms of how it works with MLS. Any questions on that? RLS is row specific. The MLS solution that we have here actually can be done by column. What we've not implemented is what's known as cell level, which would be where you'd have a different, potentially in the same column different levels in each row. So you can either label it by column or you can label it by row. But in the context of a database, I'm not sure it makes a lot of sense to try and do cell level. But that has been something that's been discussed. If you wanted to do your filtering using app user, then that column would need to be there. But I'll show you how the way we're doing MLS is what we're calling a security label column. So we're going to use the same functionality in a very similar way to implement MLS at a row level. And the reason that it works that way was kind of a design decision when RLS was first put into Postgres. There were discussions about how to best do RLS. And the decision was that doing it this way is the most flexible way and therefore can handle the most use cases. So there are some downsides to that in that this column is visible to basically to look at. And so it may not feel as good as maybe something that was hidden, but there are ways that you can deal with that too. Well, yeah, for this specific, right. If you want to be able to filter your rows based on who's logged in right now, then you need something in the row that can be compared to the current logged in user in order to do the filtering. It can be any expression that returns Boolean, true false. Okay, so now I'm gonna talk a little bit about SCLinux. How many people here are familiar with SCLinux? Oh, good number, that's good. How many people here would say that they really truly understand SCLinux? No, I'm not sure I would. I guess it depends on where you draw that bar, but so as I mentioned earlier, SCLinux is a mandatory access control system which in contrast to a discretionary access control. Discretionary access control is like you create a file on the system and you can change the permissions of that file such that anyone can read it if you decide to do that. Or if you create a table, if you're allowed to create a table on Postgres, you can grant access to that table to whoever you want. That's discretionary access control. Manitory access control means that the system itself has policies in place that are enforcing certain rules. So it's not up to the user to decide who gets to access the data. That's kind of the key difference. It's enforced in the kernel, SCLinuxes. And it's managed via these policies and when you install Red Hat 7 these days, it comes with SCLinux by default on in what's called targeted policy, targeted mode. Targeted is sort of a stripped down version of SCLinux where only certain things are controlled and everything else is still wide open. And I think they did that because SCLinux is hard to get right and in order to get people to actually use it, this was the best way. It also comes with this MLS policy which is what we're gonna use here. MLS policy is what is going to enable us to do this level and category filtering. And in our case, we also had to do some customized policy modules. Oh, one thing I'll point out to you on the slides here and the slides will be available later. I put a link on the slide, see if I've got a connection, maybe I don't. I didn't set, oh yeah, it did, it's just slow. So there's a guy at Red Hat who is kind of like the SCLinux guru and he produced this SCLinux coloring book to kind of explain SCLinux in the most basic terms. And it's actually pretty useful if you go through it. It will help you understand how SCLinux works and what it does. So I would encourage you to go look at that. MLS itself is based on something called a Bell Lepagella module. And there's like research papers written on this stuff. So I'm not gonna try and go into the details, but if you boil it all down what it really comes down to is you should be able to read at your level and below and you should be able to write at your level and up. But because there's some kind of strange things you can get into with write up, SCLinux or Red Hat at some point at least decided that they were gonna modify this model slightly and basically say that whatever you write is gonna be equal to the level that you're logged in at. So if you're logged in to SCLinux at level S6, then data that you create by default is gonna be at level S6. But if you wanna read something that's labeled S0 you'll be able to read it. Everything about how things are enforced in SCLinux comes down to these security contexts. So this is what a security context actually looks like. It's got a role component or a user component or role component, a domain component. And then the sensitivity and category that we've already been talking about. And you can think of these two things as the level, the security level. And these three things combined are more along the lines of a role-based access control. They define things that you can and can't do in the system. So some examples of what that might look like. You'd have a DB user, a DB client R, a DB client T and level S0. That's something we'll see later on in the examples. And you might have an object on the system like a row and a table or a table itself that's labeled like this. System U, object R, SCPG SQL table T. And then you can see this, this defines a range of sensitivities and this defines a range of categories. So basically this here is saying that this table would be able to contain data at any level. In terms of these levels, S0 through S15, it's a range. You can alias these things so you can say that S0 equals green and S4 equals yellow and S5 equals orange, if that's what you wanna call them. And hierarchical dominance is defined. This is what I'm saying before about if you're logged in with an S6 level, you should be able to look at data that's at S0. So the level that you're at dominates the object. But these categories which are also, this represents a group instead of a dash, it's a dot, you can also alias those things but these things are not hierarchical. Just because I have C1023, it doesn't mean I can see stuff that's labeled with C1. I have to actually have C1 to view C1. In SE Linux, security access decision, this is when the kernel is gonna decide does a particular subject context. So in our case, it's gonna be the Postgres user and with a particular object or target context and so in this case, we're talking about a table row or maybe a table, maybe a column but for the most part for this presentation we're talking about table rows. And there's some kind of a permission, something I'm trying to do to that object. So I'm trying to select it, I'm trying to delete it, I'm trying to update it, whatever. It combines those three things to decide whether or not that subject with that object and that action is allowed to occur. So type enforcement will say, are you allowed to, this is where that user role and domain come in. Is this subject even allowed to do this type of access to this type of object? That's the first decision that's gotta be made. If you're not even allowed to select from this table based on a role-based access control you'll be blocked right there. Assuming you pass that then where MLS is concerned then we'll come into looking at the sensitivity in the category. So if I've got S5 then I should be able to see something that's labeled as S3 but if I've got S5, C1 to C5 that does not include S3, C42. So in that case I would not get to see that. So the third component of this solution is something called SCPG SQL. It's an extension and contrib in Postgres. It's been there I think since Postgres 9.1. And the basic idea here is that Postgres is modified at the time that SCPG SQL is developed to support something called security label command. So it's a way that I can specifically say that this object in the database has some label. As far as Postgres is concerned that's really about all there is to it. Postgres doesn't do anything with that label by itself. It's just providing a place to store it. It depends on a label provider that actually uses the label and SCPG SQL is the label provider. So in this case we're gonna use that label to label the object with an SC Linux object context and use SC Linux to make these decisions about access. Now what's there in stock Postgres wasn't quite suitable for our needs so we had to modify it. At this point in time these modifications are still not open sourced but our full intent is to either push this stuff back into the community SCPG SQL maybe in 9.7 or whatever the community wants to accept out of it and to the extent that some of it doesn't get accepted we will open source our own version of SCPG SQL on GitHub or something like that. But what we've done is we've taken care of a mapping of the database user to an SC Linux user so that when I log in to the database as Joe I can say that Joe actually maps to some SC Linux user on the system. We're also taking care of us context transition based on the user and the network. So that means that based on who the user is mapped to and I'll show you an example of this in a few slides and based on the network that the user logged in on as I talked about earlier I'm gonna decide what the label, what the context of that current connection is gonna be. And then the two main functions that we've added are this check row label and create row label. And so these are going to be used in these RLS policies to create a label for a row that we're inserting or changing and to verify or filter what rows we can see based on who we are. In terms of security label support, Postgres right out of the box supports labeling of all these objects and as I just said we're kind of customizing SCPG SQL to add support for labeling of rows. This check row label takes two arguments, one of them is optional. The first argument is supposed to be the row security label. The subject context is gonna be based on the client so it's the SC Linux user combined with the network. And then R2 if it's there is gonna be a permission type so it's defaults to select but you can specify that I want to check to see whether this user for this row can do insert, update, delete and there's also relabel permissions as well. And then SC Linux is making the decision. Returning the Boolean from this which is used in that using expression in the policy for RLS.