four_iam/resource/
role.rs1use four::{
2 arn::Arn,
3 convert::{WillBe, WillMappable},
4 function::{
5 getatt::{Attribute, HaveAtt},
6 reference::{RefInner, Referenced},
7 },
8 logical_id::LogicalId,
9 service::IAM,
10 ManagedResource,
11};
12use serde::Serialize;
13
14use crate::property::{
15 action, policy_document::PolicyDocument, principal::Principal, statement::Statement,
16};
17
18#[derive(ManagedResource, Clone)]
19#[resource_type = "AWS::IAM::Role"]
20pub struct Role {
21 logical_id: LogicalId,
22 assume_role_policy_document: PolicyDocument,
23 description: Option<String>,
24 role_name: Option<WillBe<RoleName>>,
25 managed_policy_arns: Option<Vec<WillBe<Arn<IAM>>>>,
26}
27
28impl Role {
29 pub fn new(assume_role_policy_document: PolicyDocument, logical_id: LogicalId) -> Self {
30 Self {
31 logical_id,
32 assume_role_policy_document,
33 description: None,
34 role_name: None,
35 managed_policy_arns: None,
36 }
37 }
38
39 pub fn assume_role(id: LogicalId, principal: Principal) -> Self {
40 let statement = Statement::allow()
41 .action(vec![Box::new(action::sts::AssumeRole)])
42 .principal(principal);
43 let policy_document = PolicyDocument::latest(vec![statement]);
44
45 Self::new(policy_document, id)
46 }
47
48 pub fn description(mut self, description: &str) -> Self {
49 self.description = Some(description.to_string());
50 self
51 }
52
53 pub fn name(mut self, name: WillBe<String>) -> Self {
54 self.role_name = Some(name.map());
55 self
56 }
57
58 pub fn managed_policy_arns(mut self, arns: Vec<WillBe<Arn<IAM>>>) -> Self {
59 self.managed_policy_arns = Some(arns);
60 self
61 }
62}
63
64impl Referenced for Role {
65 type To = WillBe<RoleName>;
66
67 fn referenced(&self) -> RefInner {
68 RefInner::Id(self.logical_id.clone())
69 }
70}
71
72#[derive(Debug, Clone, Serialize)]
73pub struct RoleName(String);
74
75impl RoleName {
76 pub fn new(name: String) -> Self {
77 Self(name)
78 }
79}
80
81impl WillMappable<String> for RoleName {}
82
83#[derive(Debug, Clone, Serialize)]
84pub struct RoleArn(Arn<IAM>);
85
86impl From<Arn<IAM>> for RoleArn {
87 fn from(value: Arn<IAM>) -> Self {
88 RoleArn(value)
89 }
90}
91
92#[derive(Debug, Clone, Serialize)]
93pub struct RoleId(String);
94
95impl HaveAtt<RoleArn> for Role {}
96impl HaveAtt<RoleId> for Role {}
97
98impl Attribute for RoleArn {
99 fn name() -> &'static str {
100 "Arn"
101 }
102}
103
104impl Attribute for RoleId {
105 fn name() -> &'static str {
106 "RoleId"
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use crate::property::action;
114
115 #[test]
116 fn test_role1() {
117 let role_id = LogicalId::try_from("role-id").unwrap();
118 let statement = Statement::allow()
119 .action(vec![Box::new(action::sts::AssumeRole)])
120 .principal(Principal::from(ServicePrincipal::Lambda));
121 let assume_role_policy_document = AssumeRolePolicyDocument::latest(vec![statement]);
122 let role = Role::new(assume_role_policy_document, role_id);
123 let mut rhs = r#"{
124 "Type": "AWS::IAM::Role",
125 "Properties": {
126 "AssumeRolePolicyDocument": {
127 "Version": "2012-10-17",
128 "Statement": [
129 {
130 "Effect": "Allow",
131 "Action": [ "sts:AssumeRole" ],
132 "Principal": {
133 "Service": [ "lambda.amazonaws.com" ]
134 }
135 }
136 ]
137 }
138 }}"#
139 .to_string();
140 rhs.retain(|c| c != ' ' && c != '\n');
141 assert_eq!(serde_json::to_string(&role).unwrap(), rhs);
142 }
143}