[00:00.980 --> 00:03.960] I'm Nimrod. I'm a solution architect at BridgeCrew. [00:03.960 --> 00:07.880] And over the next 35 minutes or so, I'd love to walk you through [00:07.880 --> 00:11.100] how you can utilize open source to do least privilege [00:11.100 --> 00:14.260] using infrastructure as code. Sorry. [00:15.480 --> 00:19.300] So, a bit about me. I'm a solution architect at BridgeCrew. [00:19.300 --> 00:22.000] BridgeCrew is a cloud security company that helps identify [00:22.000 --> 00:24.940] misconfigurations in both real cloud environments [00:24.940 --> 00:29.060] and infrastructure as code frameworks, such as Terraform, CloudFormation, etc. [00:29.060 --> 00:32.200] And we're doing all of this using grid automation. [00:32.380 --> 00:35.180] As part of my role in BridgeCrew, I'm involved with a few [00:35.180 --> 00:38.720] open source projects around AWS and Terraform, [00:38.720 --> 00:41.440] and security, which I either co-maintain [00:41.440 --> 00:43.940] or contribute to continuously. [00:44.180 --> 00:48.080] And my newest open source tool is called AirIAM, [00:48.080 --> 00:51.300] which I hope at the end of this talk you'll also be a fan of. [00:52.220 --> 00:53.700] Let's dive in. [00:54.820 --> 00:57.320] So, just a quick overview. [00:57.320 --> 01:00.820] AWS AirIAM is a service by AWS that manages [01:00.820 --> 01:04.200] all the privileges in your AWS account, [01:04.200 --> 01:07.180] in every AWS account. That means it includes [01:07.180 --> 01:10.340] all the privileges both for things that you need, [01:10.340 --> 01:13.280] your employees, your servers, [01:13.280 --> 01:15.760] but also for things that run in the background, [01:15.760 --> 01:19.540] like AWS services and access across services. [01:20.700 --> 01:24.400] So, it starts out really cool, and it allows that for everything. [01:24.400 --> 01:26.740] But the problem is that it is hard because [01:26.740 --> 01:30.720] it includes a lot of specifics and details. [01:30.900 --> 01:33.880] You create a user for every employee, and maybe [01:33.880 --> 01:37.320] for integrations, and for your CICD pipeline, [01:37.320 --> 01:40.800] and your servers, and it just becomes way too hectic. [01:41.240 --> 01:43.980] So, let's try to break it down and see [01:43.980 --> 01:45.940] why it is that way. [01:46.660 --> 01:49.760] When I look at AIAM, I think of it [01:49.760 --> 01:52.740] more like a road system. So, we have our users [01:52.740 --> 01:55.920] and our servers, and we have the resources, [01:55.920 --> 01:59.020] our data, our buckets, our databases, [01:59.020 --> 02:00.820] and all of those are destinations. [02:01.500 --> 02:05.220] And IAM, or privileges that are described in IAM, [02:05.220 --> 02:07.780] are like the roads between those entities. [02:08.600 --> 02:11.800] So, usually when you start out, you don't need a road planner. [02:11.800 --> 02:14.460] You have maybe two or three employees, [02:14.460 --> 02:17.300] and you set up maybe a server. That server [02:17.840 --> 02:20.480] serves your app. It can be behind a load balancer. [02:20.820 --> 02:23.520] It's pretty simple stuff. You won't need more than maybe [02:23.520 --> 02:27.200] two or three roles and top four or five users. [02:27.200 --> 02:29.820] But we don't use the cloud for this [02:29.820 --> 02:32.740] simple infrastructure. We use the cloud because it allows us [02:32.740 --> 02:35.680] to grow and scale and use more [02:35.680 --> 02:38.520] and more services. And sooner rather than later, [02:38.520 --> 02:41.780] you'll find yourself stuck in this kind of situation. [02:41.780 --> 02:44.760] You'll be adding more services, RDS, [02:44.760 --> 02:48.020] ECS, CloudFormation, CloudFront, [02:48.020 --> 02:50.240] more and more services, and all of those [02:50.240 --> 02:53.480] require different roles and different users. [02:53.580 --> 02:56.940] Some of them are maybe even third-party tools. [02:56.940 --> 02:59.740] And you also have different access patterns. [02:59.740 --> 03:02.680] You can start out by everybody using their own [03:02.680 --> 03:05.400] IAM users and then switch out [03:05.400 --> 03:08.600] to maybe using SSO and identity providers, [03:08.600 --> 03:12.280] which mean you have roles and not set of credentials. [03:12.280 --> 03:14.360] And all of that leaves layer [03:14.360 --> 03:17.920] over layer of unused and unnecessary privileges, [03:17.920 --> 03:21.700] which can be used by bad actors. [03:22.280 --> 03:24.060] Now, as a security person, [03:24.060 --> 03:26.900] which is kind of what I do, when I [03:26.900 --> 03:29.980] see IAM, I have only one question I really want [03:29.980 --> 03:33.560] to answer. And that is, who has access to what? [03:34.400 --> 03:36.100] It should be pretty simple, [03:36.100 --> 03:38.660] but I will now show you why it isn't that simple, [03:38.660 --> 03:41.880] specifically in AWS IAM, but that happens also in [03:41.880 --> 03:45.320] GCP, Azure, and other cloud providers. [03:45.900 --> 03:49.040] So let's start out with a simple question. [03:49.080 --> 03:51.560] Who has admin access, which is full [03:51.560 --> 03:53.720] access, to my AWS account? [03:54.280 --> 03:57.520] When I asked this question in the beginning, naturally [03:57.520 --> 04:00.380] I went to the administrator access, which is a managed AWS [04:00.380 --> 04:03.620] policy, and I tried to understand who has access [04:03.620 --> 04:06.580] to that policy. Who has that policy attached? [04:06.720 --> 04:09.520] So you can see here, this is an example account. [04:09.520 --> 04:12.480] We have two roles, which have admin [04:12.480 --> 04:15.620] access to the account, and also a group. Now, [04:15.620 --> 04:18.300] the group in itself is not any user [04:18.300 --> 04:21.400] or role, but we would like to know who is part of that group. [04:21.400 --> 04:24.160] So I clicked on the group, and now I see the group [04:24.160 --> 04:27.460] has 11 users, all of them have admin access to the [04:27.460 --> 04:30.360] account. The problem with IAM [04:30.360 --> 04:33.620] in AWS is that this isn't a complete list [04:33.620 --> 04:35.520] of all the admins in the account. [04:36.260 --> 04:39.380] And the reason is simple. IAM allows you to create [04:39.380 --> 04:42.580] your own policy documents, which are simple JSONs, [04:42.580 --> 04:45.300] in which you describe what you allow and deny for each [04:46.060 --> 04:48.300] entity. It could be a role, it could be a user, [04:48.300 --> 04:51.300] it could be a group. So this is an example of an [04:51.300 --> 04:54.040] inline policy, which means it's a policy for one specific [04:54.040 --> 04:57.140] role, which allows all actions [04:57.140 --> 05:00.440] on all resources. Well, that's what I would call an [05:00.440 --> 05:03.200] admin. And this isn't listed anywhere. It won't [05:03.200 --> 05:06.200] show up anywhere. You'll have to go entity by [05:06.200 --> 05:09.100] entity, policy document by policy document [05:09.100 --> 05:11.300] to find these entities. [05:12.420 --> 05:15.200] So this example shows us two problems [05:15.200 --> 05:18.760] we have with IAM. One is that it is easily bypassed. [05:18.760 --> 05:21.320] You can just create your own policy, it won't be [05:21.320 --> 05:24.080] listed anywhere, no one will know, and you can give any [05:24.080 --> 05:27.120] permission you'd like. The second one is that [05:27.120 --> 05:30.620] IAM supports complex relationships. Let's say you have a user. [05:30.620 --> 05:33.240] You can attach a managed policy to it, or you can [05:33.240 --> 05:36.260] put an inline policy. But as we've just seen, you can also [05:36.260 --> 05:39.280] do that using a group, right? You can have the [05:39.280 --> 05:42.420] user be a part of a group, and that group will have the policies [05:42.420 --> 05:45.200] attached or put on. But that's not [05:45.200 --> 05:48.380] all that IAM supports. IAM supports assuming [05:48.380 --> 05:51.380] role as well. So that means a user can assume [05:51.540 --> 05:54.340] a role and get the policies that are set on that [05:54.340 --> 05:57.560] role, or assume through that role another role. [05:57.560 --> 05:59.940] And that's a long chain of privilege excavation [05:59.940 --> 06:02.760] that you won't be able to see using [06:02.760 --> 06:06.260] simple console and going through the entities [06:06.260 --> 06:09.640] in IAM. But that's not all. [06:09.640 --> 06:12.080] Let's take a look at another example and see two [06:12.080 --> 06:15.080] other things we can find in IAM. So [06:15.080 --> 06:18.120] this is a list of the 11 admins from the admin group [06:18.120 --> 06:21.040] we've seen before. If we look at them, we'll see [06:21.040 --> 06:24.180] that 10 of them have access keys which are older than 90 [06:24.180 --> 06:27.340] days. So best practice is to rotate [06:27.340 --> 06:30.420] your keys every 90 days since these are static credentials [06:30.420 --> 06:33.580] that if discovered, they can be used to abuse the account. [06:34.620 --> 06:35.800] We can also see that [06:36.320 --> 06:39.420] four of these users have passwords and no [06:39.420 --> 06:42.500] MFA set. Now you might notice that most [06:42.500 --> 06:45.200] of them do not have password access. That's because we've [06:45.200 --> 06:48.400] moved over to using SSO. And these [06:48.400 --> 06:51.320] four users unfortunately did not do what was [06:51.320 --> 06:54.040] required of them, or they've been handled since then. [06:54.040 --> 06:57.100] But they do pose [06:57.100 --> 06:59.900] brute force risk to the account just by having passwords [06:59.900 --> 07:03.100] with no MFA. And if that's not enough, we also [07:03.100 --> 07:05.880] see that two users have not been used for [07:05.880 --> 07:09.000] more than half a year, more than 200 days. There's [07:09.000 --> 07:11.500] really no reason to keep live access keys [07:11.960 --> 07:14.900] that have such a high level of access to the [07:14.900 --> 07:18.220] account without them being used at all. [07:18.400 --> 07:21.120] So this example shows us two things. [07:21.120 --> 07:24.280] One is that it's difficult to enforce patterns over time. [07:24.280 --> 07:26.660] You have to manually go through the user list [07:26.660 --> 07:29.720] and find the, I would say, the [07:29.720 --> 07:32.200] people who are out of line [07:32.980 --> 07:36.080] or the resources that are misconfigured. [07:36.080 --> 07:38.960] But it's also hard to trace and verify usage. It could be that [07:39.080 --> 07:42.100] a person was using this account a lot for a year [07:42.880 --> 07:44.880] and has since stopped, but [07:44.880 --> 07:47.900] we won't know it unless we check. And we have to check it [07:47.900 --> 07:51.540] per user, per role, per entity in IAM. [07:53.160 --> 07:53.740] So [07:53.740 --> 07:56.180] we have all of these problems which cause [07:56.790 --> 07:59.660] layer and layer of garbage and stuff that's left behind [07:59.660 --> 08:03.460] and waiting to be now used. [08:03.480 --> 08:06.160] And we were wondering how we can do it. [08:06.160 --> 08:08.620] So what I developed [08:08.620 --> 08:11.540] is called Air IAM. It's completely open source. You can [08:11.540 --> 08:14.780] check out the link. I'll share it later too. [08:14.780 --> 08:17.400] And what it does is distribute IAM through [08:17.400 --> 08:20.340] Terraform. It creates Terraform code from your [08:20.340 --> 08:23.440] existing IAM. Let's walk through and see [08:23.440 --> 08:24.960] what it does. [08:25.560 --> 08:29.240] So before we created the open source, obviously, we had to do [08:29.420 --> 08:31.880] a few manual iterations to see [08:31.880 --> 08:35.240] what works and what doesn't. And we came [08:35.240 --> 08:38.280] to this flow of conclusions [08:38.280 --> 08:41.560] and actions. So at first [08:41.560 --> 08:44.720] we would like to collect all the IAM entities from the [08:44.720 --> 08:47.920] account and their usage using AWS [08:47.920 --> 08:50.720] APIs, maybe CloudTrail data and so [08:50.720 --> 08:53.260] forth. And then for each entity [08:53.260 --> 08:56.760] cross-reference it with its usage and decide [08:56.760 --> 08:59.800] whether the entity is in use or not. Whether the entity is [08:59.800 --> 09:02.780] in use or not is a question that depends on [09:02.780 --> 09:05.640] the threshold for usage. I would [09:05.640 --> 09:08.580] say the default best practice is 90 days. [09:08.580 --> 09:11.600] I've seen it go down to 30 or up to 365 [09:11.600 --> 09:14.380] days. So it really depends on your preference. [09:14.660 --> 09:17.480] Once we've decided what's not used, it's easy. We can mark [09:17.480 --> 09:20.360] it for division. And we will need to go through the [09:20.360 --> 09:22.340] permissions that are in use. [09:22.780 --> 09:26.220] So we will have to go through the entities [09:26.220 --> 09:29.300] and look at their permissions, look at what [09:29.300 --> 09:32.300] they've actually used using Access Analyzer or [09:32.300 --> 09:35.300] CloudTrail and create, I would say, [09:35.580 --> 09:38.520] a minimized version of the policies that they have [09:38.520 --> 09:41.320] based only on stuff that they use, meaning we won't [09:41.320 --> 09:44.920] be able to impair any workloads, [09:44.920 --> 09:47.660] not dev, not production, not anything. If it is [09:47.660 --> 09:50.680] in use, we're leaving it as is. The third [09:50.680 --> 09:53.640] one is to create a recommendation. That [09:54.500 --> 09:56.520] usually included a very [09:57.380 --> 09:59.580] large workbook with a few sheets in it [09:59.580 --> 10:02.640] that describes what we want to do for each entity with [10:02.740 --> 10:05.660] a few different, I would say, categories. [10:05.920 --> 10:08.720] And after we've done that, we'll take that to the relevant [10:08.720 --> 10:11.260] account stakeholder or [10:11.260 --> 10:14.340] the person who actually uses the account and knows [10:14.340 --> 10:17.500] the types of usage in the account. [10:17.500 --> 10:20.700] For approval, that might [10:20.700 --> 10:23.340] seem like a pretty long process. You actually [10:23.340 --> 10:26.500] won't understand how long it is. I've added [10:26.500 --> 10:29.680] some time estimations to the different steps. I would [10:29.680 --> 10:32.580] say the most difficult part is to create [10:32.700 --> 10:35.420] a recommendation and then get the approval from the relevant [10:35.420 --> 10:38.300] stakeholders. I've seen it take weeks [10:38.300 --> 10:41.660] and it's just a lot of misunderstanding [10:41.660 --> 10:43.760] and meetings and getting [10:44.500 --> 10:47.560] formal approval. And then I found out that [10:47.560 --> 10:50.360] even implementing the changes after I have the action items [10:50.360 --> 10:53.360] and I have the approval, it takes me a while. An [10:53.360 --> 10:56.480] hour is for a medium-sized account. [10:56.480 --> 10:58.780] It could take a lot longer for bigger accounts. [11:00.260 --> 11:02.500] So after iterating through this a few [11:02.500 --> 11:05.840] times and making sure that we understand what we need, [11:05.840 --> 11:08.440] we decided, like we do in many other [11:08.440 --> 11:11.960] fields here at Bridgecrew, that we want to automate it. [11:12.380 --> 11:14.000] When we wanted to build [11:14.000 --> 11:17.400] the automation, we decided that we have [11:17.400 --> 11:20.400] four main, I would say, goals we [11:20.400 --> 11:23.100] wanted to reach through the automation tool. [11:23.100 --> 11:26.120] So the first one is that we want to identify unused [11:26.120 --> 11:29.200] entities and easily remove them. When I say [11:29.200 --> 11:32.380] unused entities, I also mean unused policy attachments. [11:32.380 --> 11:35.180] So that means policies that are not in use at all by the [11:35.180 --> 11:38.260] role or user or group that has that [11:38.260 --> 11:41.060] policy attached. I want to also remove that. [11:41.500 --> 11:44.620] We want to be able to detect drifts and enable rollback. [11:44.620 --> 11:47.180] Let's say I made some modification and it caused [11:47.180 --> 11:50.260] downtime. For some reason, something went wrong. [11:50.260 --> 11:54.380] I can always roll back and make sure everything works. [11:54.960 --> 11:56.660] I want to be able to handle scales [11:56.660 --> 11:59.760] of thousands of entities. Again, when I say entities, [11:59.760 --> 12:02.760] also the relationships between the users and the policies [12:02.760 --> 12:05.680] and the roles and the groups. So it very easily [12:05.680 --> 12:09.220] reaches the 1,000, 2,000 threshold on big accounts. [12:09.640 --> 12:11.420] And then the fourth one, [12:11.420 --> 12:14.440] which is very important, is to be able to take [12:14.440 --> 12:18.080] the plan to get approval from the relevant stakeholders. [12:18.080 --> 12:20.720] But I want something that I can share and people will [12:20.720 --> 12:24.260] easily understand and either say that's fine or not. [12:25.640 --> 12:27.500] So the tool itself, [12:27.500 --> 12:30.020] ARIAM, is pretty easy. All it does is [12:30.020 --> 12:32.740] collect data from AWS APIs, both [12:32.740 --> 12:36.320] IAM and Access Advisor, cross-references it [12:36.320 --> 12:38.840] and either outputs it as CLI [12:38.840 --> 12:42.060] output for your convenience or [12:42.060 --> 12:45.040] Terraform code, which we'll see in a bit how [12:45.040 --> 12:47.580] that, I would say, leverages [12:47.580 --> 12:49.560] the power to the maximum. [12:50.840 --> 12:53.600] So let's start talking about the tool. [12:54.560 --> 12:56.700] ARIAM contains three commands [12:56.700 --> 13:00.060] built in. The first one is called Find Unused. [13:00.060 --> 13:02.580] What it does is collect all of the data from [13:02.580 --> 13:05.740] the APIs and decides whether the entity is [13:05.740 --> 13:08.640] used or not. The default setting is [13:08.640 --> 13:12.520] 90 days. Let's do a short demo and see how it works. [13:13.620 --> 13:16.940] Great. So I've already installed [13:16.940 --> 13:19.140] ARIAM on this computer, although it is [13:19.140 --> 13:21.740] very easy to install. And I can just run [13:22.280 --> 13:24.780] ARIAM Find Unused. [13:26.080 --> 13:28.080] So it now gets all the IAM [13:28.080 --> 13:31.160] configurations for the account. It will then collect the usage [13:31.160 --> 13:33.940] for all the users and the roles in the account. And [13:33.940 --> 13:37.080] right after that, it will output all [13:37.080 --> 13:39.980] the findings. Awesome. So you can see [13:39.980 --> 13:43.420] it's generating the reports, editing it, [13:43.420 --> 13:46.080] and now it will start outputting the unused [13:46.080 --> 13:48.980] entities that it found in the account. So as you can see, we [13:48.980 --> 13:52.120] have here four users who have not been used. [13:52.120 --> 13:54.920] It says last used 365 days ago. [13:54.920 --> 13:57.840] That's the maximum that AWS promises that [13:57.840 --> 14:00.920] there was no usage in. We can [14:00.920 --> 14:04.420] also see there's one active access key that isn't being used. [14:04.580 --> 14:06.900] You'll notice that it's for a user that's not [14:06.900 --> 14:09.580] listed under the unused users. So [14:10.340 --> 14:12.740] ARIAM does not give you duplicate results. If [14:12.740 --> 14:16.200] the user is unused, it won't say that its access keys are unused, [14:16.200 --> 14:19.280] although he might have access keys that are unused. [14:20.180 --> 14:21.180] Sorry. [14:21.400 --> 14:24.640] We also have one user, that's my user, which [14:24.640 --> 14:27.840] has password access to the console with MFA, [14:27.840 --> 14:30.420] but hasn't used it for over 100 days. [14:31.100 --> 14:33.720] If it doesn't have MFA, it will say it here. [14:33.720 --> 14:36.400] So you'll be able to understand who is, I would say, [14:36.400 --> 14:39.600] the bigger problem. We also have [14:39.600 --> 14:42.600] four roles which are unused. Those are roles [14:42.600 --> 14:45.600] that haven't been used for, I'd say, over [14:45.600 --> 14:48.640] 100 days. Yes. We have two groups which [14:48.640 --> 14:51.800] are redundant. One of them has no members, which means [14:51.800 --> 14:54.460] it's just laying there and it's a security hazard [14:54.460 --> 14:57.480] because, let's say, it does have any policies attached. [14:57.480 --> 15:00.720] If you attach a user to it, it will automatically gain [15:00.720 --> 15:03.140] all those permissions. So even [15:03.560 --> 15:06.760] it's just leaving behind privileges that maybe an attacker can [15:06.760 --> 15:10.540] utilize. And then group without policies. [15:10.540 --> 15:12.540] Groups can have members but have no policies [15:12.540 --> 15:15.760] attached. And since a group is not an entity [15:15.760 --> 15:18.700] that can be used in AWS, just [15:18.700 --> 15:21.720] groups' privileges, there's no point in having those [15:21.720 --> 15:24.780] groups. And since we want to make [15:24.780 --> 15:27.940] AWS IAM as manageable as possible, [15:27.940 --> 15:30.600] it also recommends deleting those kinds of groups. [15:31.000 --> 15:33.940] We have a redundant policy that's a policy that's not [15:33.940 --> 15:37.000] attached to any user, group, or role. It's just [15:37.000 --> 15:40.340] clutter that's being left behind in the account. [15:40.340 --> 15:42.640] And we also have two policy attachments. [15:42.640 --> 15:45.140] For policies that are unused by the relevant [15:45.780 --> 15:49.220] principle. So this user, S3User1, [15:49.220 --> 15:51.840] is not using any privileges given to him by Amazon [15:51.840 --> 15:54.940] API Gateway Administrator. But he does have that privilege [15:54.940 --> 15:58.140] given to him, which can cause him to make [15:58.140 --> 16:01.060] actions which he shouldn't, such as creating or even deleting [16:01.060 --> 16:03.500] existing API gateways. [16:04.680 --> 16:05.880] Great. [16:07.020 --> 16:10.720] So I hope we've got all of that clear. [16:10.720 --> 16:13.200] And this helps us actually create some [16:13.200 --> 16:16.180] of the permissions baseline, since it allows us to remove [16:16.180 --> 16:19.400] attachments of policies that are unused but given. [16:19.400 --> 16:22.080] And create more of a list privilege model for [16:22.080 --> 16:25.080] our IAM. The second command is called [16:25.080 --> 16:28.060] recommend groups. What it does is try to look [16:28.060 --> 16:31.060] through the users that you have in the [16:31.060 --> 16:33.740] account, group them according to their [16:33.740 --> 16:36.880] relevant privileges, and actually [16:38.020 --> 16:40.180] create recommendations for three [16:40.180 --> 16:43.140] types of groups currently. One is the admins group, which are [16:43.140 --> 16:46.440] active admins. The second one is power users, [16:46.440 --> 16:49.100] which are for users who have write access to the account [16:49.100 --> 16:52.020] but not admin access. And the third one [16:52.020 --> 16:54.420] is the read-only group. That's relevant for [16:54.940 --> 16:57.980] all the users who have read access to the account but don't have any [16:57.980 --> 17:00.960] write access. This command [17:00.960 --> 17:03.700] helps us finalize the permissions baseline or [17:03.700 --> 17:06.800] the changes we want to... the things that are in use [17:06.800 --> 17:10.100] and create the recommendation, what we want the account to look [17:10.100 --> 17:13.280] like in the end. So let's [17:13.280 --> 17:14.440] see that as well. [17:15.800 --> 17:18.380] I'll hit ARIM, recommend [17:20.840 --> 17:21.710] groups. [17:23.420 --> 17:24.540] Awesome. [17:24.540 --> 17:27.940] So in this account, we have two active users. [17:27.940 --> 17:30.780] One is my user, which is an admin and requires admin [17:30.780 --> 17:33.640] access. And also this S3 user one, [17:33.640 --> 17:36.400] which has write access to S3. [17:36.400 --> 17:39.720] We don't have any read users in this account, so it doesn't [17:39.720 --> 17:42.760] offer me the read-only. There's no point in creating empty groups [17:42.760 --> 17:45.800] as we've talked before, but if there were any, it would show them [17:45.800 --> 17:46.480] here. [17:48.800 --> 17:52.140] So we have the recommendation, it's just not actionable yet. [17:52.140 --> 17:54.780] We have everything we want to do, but we can't show it [17:54.780 --> 17:58.320] to anyone and we can't just hit play and make that work. [17:58.580 --> 18:00.840] That's where the third command comes in. [18:00.840 --> 18:03.440] It's called ARIM Terraform. And what it does is create [18:03.440 --> 18:06.640] Terraform code and state file. I'll show you [18:06.640 --> 18:09.260] how it works and we'll talk a bit about Terraform [18:09.260 --> 18:13.140] so you understand all the power that this command brings with this. [18:14.160 --> 18:15.280] So, [18:15.280 --> 18:17.480] I'll type in ARIM Terraform [18:18.360 --> 18:21.500] and what it does is it will initialize Terraform, [18:21.500 --> 18:24.360] it will create Terraform files for me, and then it will import [18:24.360 --> 18:27.380] the existing Terraform entities into the local [18:27.380 --> 18:29.800] state file. Let's see how that looks. [18:30.120 --> 18:33.100] So I'll change to the results there [18:33.100 --> 18:36.840] and you'll see that it created just now. [18:36.840 --> 18:39.640] This is in my time zone. It created [18:39.640 --> 18:42.940] the .terraform directory, which includes all the [18:42.940 --> 18:45.820] files that are necessary by Terraform to run. [18:45.820 --> 18:48.560] This is a temporary file, so you can ignore it. [18:48.560 --> 18:51.860] It creates .tf files that define all the [18:51.860 --> 18:54.580] different entities and their relationships using Terraform [18:54.580 --> 18:57.900] HCL code. It also creates a state file [18:57.900 --> 19:00.900] and the backup, which again, you don't need to [19:00.900 --> 19:03.620] care about because it is only temporary [19:03.620 --> 19:06.400] and for system usage. Let's take a look [19:06.400 --> 19:09.620] at groups.tf. So, [19:09.620 --> 19:12.300] what this shows you is the [19:12.300 --> 19:15.720] four groups that we have in the account and the [19:15.720 --> 19:18.780] policies that they have attached, if any. So, for example, [19:18.780 --> 19:21.460] we have the admins group and the admins group has [19:21.460 --> 19:24.400] administrator access attached to it. We have a group [19:24.400 --> 19:27.560] without members and that group has two policies attached, [19:27.560 --> 19:30.560] the RDS full access and the user change password. [19:30.560 --> 19:33.420] We also have a group without policies, which [19:33.420 --> 19:36.580] has no policies attached, and the S3 group, [19:36.580 --> 19:39.140] which has the Amazon S3 full access. [19:39.700 --> 19:42.700] Just so we can see it for real, [19:42.700 --> 19:43.920] I've opened the [19:45.680 --> 19:48.340] console for it and this is the groups in the account. [19:48.340 --> 19:51.500] You'll see these are exactly the four groups we have and [19:51.500 --> 19:54.220] you can see that the group without policies actually [19:54.220 --> 19:57.240] does not have policies and the group without members has [19:57.240 --> 19:59.420] these two permissions. [20:01.460 --> 20:03.320] So, the same goes for [20:03.320 --> 20:07.260] roles. Let's see the roles file, for example. [20:07.420 --> 20:09.400] So, for every role, we'll have [20:09.400 --> 20:12.260] the role itself. We'll also have the assume role [20:12.260 --> 20:15.280] policy document and if it has any [20:15.280 --> 20:18.520] policy attachments, such as this one, it will be listed [20:18.520 --> 20:21.080] as well. You'll notice that the syntax is [20:21.080 --> 20:24.820] not using any hard-coded strings. [20:24.820 --> 20:28.060] Basically, ARN creates the entities and connects [20:28.060 --> 20:31.040] them so you can actually see who has access to [20:31.040 --> 20:33.960] what. Awesome. [20:34.120 --> 20:37.420] So, that's all the code. Let's take a look at the state file. [20:37.960 --> 20:39.840] So, the way Terraform works [20:39.840 --> 20:42.680] is it creates both the code and the state file [20:42.680 --> 20:45.980] and the state file describes what connects [20:45.980 --> 20:48.980] the entities that were defined in code with the actual [20:48.980 --> 20:52.160] ARNs in the cloud environment. So, for example, [20:52.160 --> 20:55.160] we have here the AWS IAM group admins [20:55.160 --> 20:57.980] as we've seen it in the code and that's connected [20:57.980 --> 21:00.900] to this instance with this ARN. [21:01.160 --> 21:03.640] So, if I copy it and I go to admins, [21:04.060 --> 21:06.840] that's exactly the ARN of the group. So, that means [21:06.840 --> 21:09.760] this code describes [21:09.760 --> 21:13.000] this group and when I [21:13.000 --> 21:16.180] will run Terraform apply or Terraform destroy or Terraform [21:16.180 --> 21:19.100] plan, it will go and check what's configured in the [21:19.100 --> 21:22.040] code and what's configured in the state file and [21:22.040 --> 21:24.960] fix the differences. So, if it needs to delete [21:24.960 --> 21:27.480] or create or modify anything that's been [21:28.080 --> 21:30.960] described in the code and is not as is in the [21:30.960 --> 21:34.780] console, in the actual account, it will be fixed. [21:36.640 --> 21:37.680] Awesome. [21:38.080 --> 21:38.900] So, [21:40.000 --> 21:42.960] once I've created this, I can actually create the [21:42.960 --> 21:45.660] Terraform code, if you'd like, without the import stage [21:45.660 --> 21:48.120] which takes a while. [21:49.840 --> 21:51.920] So, this is what it does [21:51.920 --> 21:54.840] and if I type ls-la, [21:54.840 --> 21:57.360] you'll see that everything has updated [21:57.360 --> 22:00.340] except, well, it just finished now. [22:00.380 --> 22:03.340] So, if I run it again, you'll see that everything will change [22:03.340 --> 22:06.640] except the state file. See that? Awesome. [22:06.640 --> 22:09.300] So, the state file did not change, but all the tf files [22:09.300 --> 22:10.540] got updated. [22:11.580 --> 22:13.640] So, if I go into the results [22:13.640 --> 22:16.880] and type Terraform plan, [22:16.880 --> 22:19.600] you'll see that all the differences that it wants [22:19.600 --> 22:22.580] to do is unrelated to actual [22:22.580 --> 22:25.400] entity modifications. This Terraform code [22:25.400 --> 22:28.480] describes the actual entities almost [22:28.480 --> 22:31.600] one-to-one. You see it has a force destroy flag [22:31.600 --> 22:34.400] added to the users. That's so when you select [22:34.400 --> 22:37.500] to destroy a user, it will actually go and [22:37.500 --> 22:40.860] destroy, including the access keys, [22:40.860 --> 22:43.540] the password access, everything. So, [22:43.540 --> 22:46.560] I'll run Terraform apply just to make sure we don't have [22:47.180 --> 22:49.320] any differences. You'll see it takes [22:49.660 --> 22:52.440] a few seconds. And then [22:52.440 --> 22:55.100] we have the Terraform output form [22:55.100 --> 22:58.360] and the actual account exactly in line. [22:58.360 --> 23:01.700] Hold on. I don't want to break it. Yes. [23:02.460 --> 23:04.500] Awesome. So, now [23:04.500 --> 23:07.400] let's say I want to delete all the unused entities that I've just [23:07.400 --> 23:10.320] found. Instead of going through and deleting [23:10.320 --> 23:13.560] one-by-one the policies and the groups and the users and the [23:13.560 --> 23:15.500] roles, I can just type here [23:16.300 --> 23:17.920] minus minus without [23:19.220 --> 23:24.710] unused. Great. So, [23:24.710 --> 23:27.610] now it created the Terraform files. But if we'll take a look, for [23:27.610 --> 23:30.530] example, at groups.tf, you'll see [23:30.530 --> 23:33.650] that we only have two groups now, which are the two groups that [23:33.650 --> 23:37.010] both have users and have policies attached. [23:37.770 --> 23:39.450] Pretty simple. [23:39.650 --> 23:42.370] Now, when I run Terraform plan again, [23:43.950 --> 23:45.650] you'll see that it offers to [23:45.650 --> 23:48.630] delete everything for me. And it will [23:48.630 --> 23:51.510] be much higher than five or ten [23:51.510 --> 23:54.530] entities. It actually plans to destroy 40 [23:54.530 --> 23:57.730] through users, roles, [23:57.730 --> 24:00.670] policies, and all the relationships between [24:00.670 --> 24:03.510] them. And it will take just a few seconds and [24:03.510 --> 24:06.510] the Terraform will apply. That's all you need. [24:07.050 --> 24:08.150] Pretty slick. [24:10.150 --> 24:11.350] Awesome. [24:12.910 --> 24:15.590] So, we've created a recommendation that's [24:15.590 --> 24:18.770] very actionable. I can take it and [24:18.770 --> 24:21.770] apply it. But I don't have any way to show it [24:21.770 --> 24:24.670] and get approval for it. But another very [24:24.670 --> 24:27.530] powerful plus side of using Terraform is that it's [24:27.530 --> 24:29.790] code. And for code, we have [24:29.790 --> 24:33.410] version control systems. I like GitHub, so these are [24:33.410 --> 24:36.470] print screens from GitHub. But basically, what you [24:36.470 --> 24:38.430] can do is commit the [24:39.150 --> 24:42.330] Terraform code that is outputted by default with [24:42.330 --> 24:45.310] everything to a master branch, check out a new [24:45.310 --> 24:48.250] branch, run it without unused, for example, [24:48.250 --> 24:51.270] and open a PR. And that PR talks [24:51.270 --> 24:54.530] in a very simple language that developers can understand, [24:56.310 --> 24:59.070] even less technical guys can understand that [24:59.070 --> 25:01.170] if there's a group here that's called group without [25:01.170 --> 25:03.690] members and has a minus in front of it, it will [25:03.690 --> 25:06.570] probably get deleted. So you can use that [25:06.570 --> 25:09.870] to actually have all the conversation around [25:09.870 --> 25:12.810] getting approval and making [25:12.810 --> 25:16.410] everything, I would say, [25:16.410 --> 25:19.670] approved or agreed upon. And then, [25:19.670 --> 25:22.190] again, just a simple Terraform apply will make all [25:22.190 --> 25:23.730] those changes for you. [25:25.190 --> 25:28.390] So that completes our entire flow. Although [25:28.390 --> 25:30.710] we have three commands to help [25:30.710 --> 25:34.470] crunch through all the data and understand the phases, [25:34.470 --> 25:36.870] in general, you can just run directly RIM [25:36.870 --> 25:39.990] Terraform, it will do all the work for you. It will find all the [25:39.990 --> 25:42.990] unused entities, it will import them into Terraform, [25:42.990 --> 25:45.010] and you'll be able to actually [25:46.470 --> 25:49.250] run it again without unused or with unused, [25:49.250 --> 25:52.830] run Terraform apply, everything will be in your hands. [25:54.210 --> 25:57.170] Now, you've run it once, that's great. You have your [25:57.170 --> 26:00.790] IAM set up clean and sparkling and beautiful. [26:00.970 --> 26:02.930] But the problem with the cloud is that [26:02.930 --> 26:06.270] well, it's both a plus and a minus, I would say, [26:06.270 --> 26:07.510] is that people can [26:09.430 --> 26:12.010] manually change and make modifications. [26:12.730 --> 26:15.510] Now, using RIM on a [26:15.510 --> 26:18.610] weekly basis, monthly basis, on a regular basis, [26:18.610 --> 26:21.110] you'll be able to scan your IAM and identify [26:21.110 --> 26:24.030] drifts in existing configurations. That means if there were any [26:24.380 --> 26:27.330] modifications or deletions, you'll be able to find [26:27.330 --> 26:30.490] those things in code and [26:30.490 --> 26:33.410] actually automatically update your [26:33.410 --> 26:36.370] Terraform state and your Terraform code. [26:36.370 --> 26:39.770] You'll also be able to identify changes in usage status. [26:39.770 --> 26:42.430] So we've seen the problem where we had admins who have been unused [26:42.430 --> 26:45.470] for a long time. If you scan on a regular basis, [26:45.470 --> 26:48.390] it will by itself find entities that have been unused [26:48.390 --> 26:51.350] for 90 days or if you modify your threshold [26:51.350 --> 26:54.370] by your threshold and mark them for deletion [26:54.370 --> 26:57.750] and recommend you delete them. It will also help you identify [26:57.750 --> 27:00.730] new configurations. So let's say you have a [27:00.730 --> 27:03.950] new team or you have a new service or you even started a new Lambda [27:03.950 --> 27:06.750] and you created a role for it, that role will [27:06.750 --> 27:09.370] automatically be integrated into your Terraform. [27:09.370 --> 27:12.450] It will be imported into your state file and you can add it [27:12.450 --> 27:15.510] to your repository where you will still have it [27:15.510 --> 27:19.290] managed and you'll be able to see it. [27:19.330 --> 27:21.430] And nothing will go without [27:21.430 --> 27:24.690] knowledge. And then the last [27:24.690 --> 27:27.370] thing that ARAM and Terraform enable [27:27.370 --> 27:30.570] to you is to use static analysis tools to identify [27:30.570 --> 27:33.570] bad practices. So I would like [27:33.570 --> 27:36.570] to take this to the next slide actually [27:36.570 --> 27:39.490] which shows, I would say, two [27:39.490 --> 27:42.030] really great tools that will help you [27:42.030 --> 27:45.650] use infrastructure as code [27:45.650 --> 27:48.570] and static analysis for your permissions [27:48.570 --> 27:51.210] in your IAM. So the first one is called [27:51.210 --> 27:54.650] Chekhov. It's also pretty easy to install and I already [27:54.650 --> 27:56.390] have it set up here. [27:56.890 --> 28:00.190] So Chekhov, what it does is identify bad practices [28:00.190 --> 28:03.690] in Terraform. So if I run... let's see... [28:04.530 --> 28:06.610] the last thing I did was without the unused [28:06.610 --> 28:09.510] right? So I want to do it one second with [28:09.510 --> 28:12.650] everything. So right now I created Terraform for [28:12.650 --> 28:15.590] the existing IAM setup. And if I go to [28:15.590 --> 28:18.070] the results tab, I can just run Chekhov [28:18.390 --> 28:21.350] minus the results. This will make [28:21.350 --> 28:24.530] Chekhov scan all the Terraform files that are in the results [28:24.530 --> 28:27.810] directory. And we'll see in a few seconds [28:27.810 --> 28:30.530] that it has quite a lot of findings. [28:30.730 --> 28:34.310] So if I scroll up, yes, quite a lot indeed. [28:34.310 --> 28:37.170] So it found, it ran 56 [28:37.170 --> 28:40.130] checks and 23 of them failed. This [28:40.130 --> 28:43.150] includes misconfigured admins and [28:43.150 --> 28:45.710] bad assumer role policies and [28:46.270 --> 28:48.990] policies that are attached directly to users as this [28:48.990 --> 28:52.170] would require justification. Otherwise, it is really [28:52.170 --> 28:55.270] recommended to use groups. Let's say [28:55.270 --> 28:57.490] I ran it without the unused, just for [28:58.250 --> 29:01.110] checking what that would mean. By deleting all the unused [29:01.110 --> 29:03.930] entities and running Chekhov again, I will see [29:03.930 --> 29:07.010] how much cleaner the account is. And the [29:07.010 --> 29:10.150] account is a lot cleaner. So we only have two failed checks [29:10.150 --> 29:12.730] and both of them can be either justified or [29:12.730 --> 29:16.130] fixed. And all in all, we only [29:16.130 --> 29:19.130] have 11 checks that were scanned. [29:19.130 --> 29:21.930] That means a lot of the overhead was cleaned simply [29:21.930 --> 29:24.690] by deleting unused stuff. [29:26.130 --> 29:27.330] Awesome. [29:28.290 --> 29:31.410] Another really cool tool is PolicySentry. [29:31.410 --> 29:34.210] PolicySentry allows you to build IAM policies [29:34.210 --> 29:36.690] from scratch using YAML syntax [29:37.330 --> 29:40.770] and easy, simple CRUD syntax. [29:40.770 --> 29:43.410] So you have create, read and [29:43.410 --> 29:46.530] update and delete syntax for different resources and [29:46.530 --> 29:49.230] different services. And that creates an IAM [29:49.230 --> 29:52.250] policy that's probably better than what [29:52.250 --> 29:55.250] your average developer would create. [29:56.190 --> 29:59.190] If you're talking about scanning your existing [29:59.190 --> 30:02.350] configurations, I also have a few tools up my [30:02.350 --> 30:05.590] sleeve. So the first one, I would say the category [30:05.590 --> 30:08.410] is finer and more granular [30:08.410 --> 30:11.550] disk privilege for IAM. [30:11.550 --> 30:14.250] We have CloudTracker by Geolabs and Ardvark [30:14.250 --> 30:17.470] plus RepoKid by Netflix. They both [30:17.470 --> 30:20.030] use CloudTrail data, so you need to have CloudTrail read [30:20.030 --> 30:23.430] access to analyze the policies and [30:23.430 --> 30:26.510] mark specific privileges and break [30:26.510 --> 30:29.390] down all the stars and the jokers in your [30:29.390 --> 30:32.310] policy to understand what you're giving that isn't really [30:32.310 --> 30:35.430] in use. I would say that CloudTrail [30:35.430 --> 30:38.230] visibility or coverage is not 100%. [30:38.230 --> 30:41.570] Not all actions are by default recorded [30:41.570 --> 30:43.930] in CloudTrail. And so using [30:43.930 --> 30:47.310] CloudTrail comes with a... [30:47.310 --> 30:48.770] maybe you should take it [30:50.270 --> 30:52.770] suspiciously. Another really [30:52.770 --> 30:55.750] cool tool that I'd like to show is called CloudSplaining. [30:55.750 --> 30:58.530] CloudSplaining is another tool by Salesforce that identifies [30:58.530 --> 31:01.530] possible risks in your IAM configurations. [31:01.530 --> 31:05.230] So it has four different classes, privilege escalation, [31:05.230 --> 31:07.650] data exfiltration, other stuff. [31:07.650 --> 31:09.950] Let me show you real quick. [31:10.270 --> 31:13.550] So I run CloudSplaining. It's a very simple [31:13.550 --> 31:16.890] setup again. So what it does [31:16.890 --> 31:19.930] is it scans all of the policies that are in the [31:19.930 --> 31:22.850] account and it outputs a very detailed and rich [31:22.850 --> 31:25.930] report about all of the stuff that you can find [31:25.930 --> 31:28.950] in your account. You can actually go by the policies [31:28.950 --> 31:32.090] or by the principles, which is what I prefer, and just [31:32.090 --> 31:33.870] take a look, for example, [31:34.670 --> 31:37.530] who has access to infrastructure [31:37.530 --> 31:40.730] modification. So say the misconfigured admin [31:40.730 --> 31:43.890] user has... well, since he's a misconfigured [31:43.890 --> 31:47.290] admin user, he has all the bad stuff that he can. [31:47.290 --> 31:51.090] If we'll take a look at the misconfigured IAM user, [31:51.970 --> 31:52.950] you'll see that [31:52.950 --> 31:56.410] he has this very bad policy, [31:56.410 --> 31:59.530] which we've talked about. It allows everything on everything. [32:00.430 --> 32:01.830] So it shows that he can [32:01.830 --> 32:05.030] do a lot of infrastructure modifications, [32:05.030 --> 32:07.970] do privilege escalation, do resource exposure, [32:07.970 --> 32:10.930] and data exfiltration. You can actually go [32:10.930 --> 32:13.730] through this by risk and start [32:13.730 --> 32:16.290] diving deeper into that. [32:18.410 --> 32:20.170] And then the final [32:20.170 --> 32:23.030] tool I'd like to show you is called PrincipleMapper [32:23.030 --> 32:25.950] or PMapper. It's by NCC Group. It helps [32:25.950 --> 32:29.570] identify possible privilege escalations in the account. [32:29.570 --> 32:32.190] So if you remember, we had the graph where a user [32:32.190 --> 32:34.750] can assume a role and that role can assume another role [32:34.750 --> 32:37.870] and each role has its own privilege, I would say [32:37.870 --> 32:40.130] policy context of policies. [32:40.690 --> 32:44.370] So this tool creates a graph. You see it here. [32:44.470 --> 32:46.710] An example, it's a very partial [32:46.710 --> 32:49.530] graph. It has these two roles [32:49.530 --> 32:52.650] and this user, for example, can assume this role. [32:52.810 --> 32:55.430] And so the user, which is called [32:55.430 --> 32:58.830] EC2 Manager, can assume the role and gain all the privileges [32:58.830 --> 33:02.050] that are attached to EC2 role for SSM. [33:02.170 --> 33:04.830] And this allows you to map all the different roles [33:04.830 --> 33:08.710] and maybe if you identify a role that is super powerful, [33:08.710 --> 33:11.070] check who can assume it and make sure [33:11.070 --> 33:13.430] that that's in check. [33:15.830 --> 33:19.390] Yep, that's it for the slideshow. [33:20.650 --> 33:21.970] All right. [33:22.790 --> 33:24.630] I guess to start off with [33:24.630 --> 33:27.670] one question for me, I'm assuming that [33:27.670 --> 33:30.430] if you wanted to make a change, a specific change [33:30.430 --> 33:33.490] instead of the whole IAM recommendation made by [33:33.490 --> 33:36.650] AIR IAM, you would just go ahead and edit the [33:36.650 --> 33:39.330] Terraform file, right? And so are there any [33:39.330 --> 33:42.470] specific config files within AIR IAM [33:42.470 --> 33:45.510] that you can use to specify what to detect [33:45.510 --> 33:48.150] and what to ignore or anything like that? [33:48.150 --> 33:50.930] So Terraform itself allows you to [33:50.930 --> 33:54.310] maybe, I would say, create or modify or destroy [33:54.310 --> 33:58.050] anything you'd like within the code and the state file. [33:58.050 --> 34:00.490] So AIR IAM gives you all of the changes you'd like. [34:00.490 --> 34:03.410] You can run Terraform apply as I did in the slideshow, [34:03.410 --> 34:05.970] but you can also specify a specific target, [34:05.970 --> 34:09.210] be it a user, a group, or a policy, and Terraform will [34:09.210 --> 34:12.530] modify only that part of the findings. [34:12.970 --> 34:16.070] Got it. And then another one, [34:16.070 --> 34:17.910] do you plan on bringing any of these [34:18.490 --> 34:21.170] features to GCP or [34:21.170 --> 34:23.490] Azure, something along those lines? [34:23.670 --> 34:27.810] Definitely. So that's something that we've heard before. [34:27.810 --> 34:30.850] We are planning to do this. It requires [34:31.190 --> 34:34.290] a complete different set of, I would say, [34:34.290 --> 34:36.990] you need to use the other [34:36.990 --> 34:39.990] SDKs and it will require more knowledge because [34:39.990 --> 34:43.770] GCP IAM is not exactly like AWS IAM. [34:43.770 --> 34:45.930] It has a lot more of privileges [34:45.930 --> 34:49.150] given by the resources and not the principles, [34:49.150 --> 34:52.270] but we are definitely planning to go in that direction. [34:52.270 --> 34:55.090] Got it. Another question [34:55.090 --> 34:57.990] from Artemis in chat. How well do these tools [34:57.990 --> 35:00.750] work in a multi-account environment? [35:01.050 --> 35:03.210] That's a great question. So [35:04.090 --> 35:07.050] I would start out by saying that IAM permissions are [35:07.050 --> 35:10.110] limited to the account. You can give cross-account [35:10.110 --> 35:12.950] permissions, but that would be from [35:12.950 --> 35:16.110] one account you give the other account permissions. [35:16.170 --> 35:18.990] So the context of every, I would [35:18.990 --> 35:22.190] say, analysis is a specific AWS account. [35:22.190 --> 35:25.430] So you can use ARAM using all the default [35:25.430 --> 35:28.530] AWS credentials tools. You can use the profile and specify [35:28.530 --> 35:31.410] the minus minus profile flag. You can use [35:31.410 --> 35:34.370] AWS environment variables to scan different accounts, [35:34.370 --> 35:37.350] but every ARAM scan is limited to the context of [35:37.350 --> 35:39.830] one account since that is the context of IAM.