From 1a3bff6cd6c4876fe1dcbc5cbed8944e2bf323b3 Mon Sep 17 00:00:00 2001 From: Dominik Richter Date: Mon, 11 Dec 2023 20:30:03 -0800 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20aws.iam.loginProfile=20added=20?= =?UTF-8?q?for=20IAM=20users?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Dominik Richter --- providers/aws/resources/aws.lr | 8 ++ providers/aws/resources/aws.lr.go | 83 ++++++++++++++++++++ providers/aws/resources/aws.lr.manifest.yaml | 10 +++ providers/aws/resources/aws_iam.go | 46 +++++++++++ 4 files changed, 147 insertions(+) diff --git a/providers/aws/resources/aws.lr b/providers/aws/resources/aws.lr index 725ba89254..6fc86df68d 100644 --- a/providers/aws/resources/aws.lr +++ b/providers/aws/resources/aws.lr @@ -777,6 +777,14 @@ private aws.iam.user @defaults("arn name") { groups() []string // List of access keys metadata associated with the user accessKeys() []dict + // Login profile for the user + loginProfile() aws.iam.loginProfile +} + +// AWS IAM login profile for a user +private aws.iam.loginProfile @defaults("createDate") { + // Time when the login profile was created + createDate time } // AWS IAM policy diff --git a/providers/aws/resources/aws.lr.go b/providers/aws/resources/aws.lr.go index 9cd79185c5..0c8230fed9 100644 --- a/providers/aws/resources/aws.lr.go +++ b/providers/aws/resources/aws.lr.go @@ -222,6 +222,10 @@ func init() { Init: initAwsIamUser, Create: createAwsIamUser, }, + "aws.iam.loginProfile": { + // to override args, implement: initAwsIamLoginProfile(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createAwsIamLoginProfile, + }, "aws.iam.policy": { // to override args, implement: initAwsIamPolicy(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createAwsIamPolicy, @@ -1545,6 +1549,12 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "aws.iam.user.accessKeys": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsIamUser).GetAccessKeys()).ToDataRes(types.Array(types.Dict)) }, + "aws.iam.user.loginProfile": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsIamUser).GetLoginProfile()).ToDataRes(types.Resource("aws.iam.loginProfile")) + }, + "aws.iam.loginProfile.createDate": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsIamLoginProfile).GetCreateDate()).ToDataRes(types.Time) + }, "aws.iam.policy.arn": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsIamPolicy).GetArn()).ToDataRes(types.String) }, @@ -4943,6 +4953,18 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlAwsIamUser).AccessKeys, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) return }, + "aws.iam.user.loginProfile": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsIamUser).LoginProfile, ok = plugin.RawToTValue[*mqlAwsIamLoginProfile](v.Value, v.Error) + return + }, + "aws.iam.loginProfile.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsIamLoginProfile).__id, ok = v.Value.(string) + return + }, + "aws.iam.loginProfile.createDate": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsIamLoginProfile).CreateDate, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) + return + }, "aws.iam.policy.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlAwsIamPolicy).__id, ok = v.Value.(string) return @@ -11992,6 +12014,7 @@ type mqlAwsIamUser struct { AttachedPolicies plugin.TValue[[]interface{}] Groups plugin.TValue[[]interface{}] AccessKeys plugin.TValue[[]interface{}] + LoginProfile plugin.TValue[*mqlAwsIamLoginProfile] } // createAwsIamUser creates a new instance of this resource @@ -12089,6 +12112,66 @@ func (c *mqlAwsIamUser) GetAccessKeys() *plugin.TValue[[]interface{}] { }) } +func (c *mqlAwsIamUser) GetLoginProfile() *plugin.TValue[*mqlAwsIamLoginProfile] { + return plugin.GetOrCompute[*mqlAwsIamLoginProfile](&c.LoginProfile, func() (*mqlAwsIamLoginProfile, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("aws.iam.user", c.__id, "loginProfile") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.(*mqlAwsIamLoginProfile), nil + } + } + + return c.loginProfile() + }) +} + +// mqlAwsIamLoginProfile for the aws.iam.loginProfile resource +type mqlAwsIamLoginProfile struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlAwsIamLoginProfileInternal it will be used here + CreateDate plugin.TValue[*time.Time] +} + +// createAwsIamLoginProfile creates a new instance of this resource +func createAwsIamLoginProfile(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlAwsIamLoginProfile{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + // to override __id implement: id() (string, error) + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("aws.iam.loginProfile", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlAwsIamLoginProfile) MqlName() string { + return "aws.iam.loginProfile" +} + +func (c *mqlAwsIamLoginProfile) MqlID() string { + return c.__id +} + +func (c *mqlAwsIamLoginProfile) GetCreateDate() *plugin.TValue[*time.Time] { + return &c.CreateDate +} + // mqlAwsIamPolicy for the aws.iam.policy resource type mqlAwsIamPolicy struct { MqlRuntime *plugin.Runtime diff --git a/providers/aws/resources/aws.lr.manifest.yaml b/providers/aws/resources/aws.lr.manifest.yaml index 185548aa49..20bb312e44 100755 --- a/providers/aws/resources/aws.lr.manifest.yaml +++ b/providers/aws/resources/aws.lr.manifest.yaml @@ -1703,6 +1703,14 @@ resources: platform: name: - aws + aws.iam.loginProfile: + fields: + createDate: {} + is_private: true + min_mondoo_version: latest + platform: + name: + - aws aws.iam.policy: docs: desc: | @@ -1769,6 +1777,8 @@ resources: createDate: {} groups: {} id: {} + loginProfile: + min_mondoo_version: latest name: {} passwordLastUsed: {} policies: {} diff --git a/providers/aws/resources/aws_iam.go b/providers/aws/resources/aws_iam.go index 68f9842e62..5b002025e8 100644 --- a/providers/aws/resources/aws_iam.go +++ b/providers/aws/resources/aws_iam.go @@ -1310,3 +1310,49 @@ func (a *mqlAwsIamUser) groups() ([]interface{}, error) { return res, nil } + +func (a *mqlAwsIamUser) loginProfile() (*mqlAwsIamLoginProfile, error) { + conn := a.MqlRuntime.Connection.(*connection.AwsConnection) + + svc := conn.Iam("") + ctx := context.Background() + name := a.Name.Data + + profile, err := svc.GetLoginProfile(ctx, &iam.GetLoginProfileInput{ + UserName: &name, + }) + + var ae smithy.APIError + if errors.As(err, &ae) { + if ae.ErrorCode() == "NoSuchEntity" { + a.LoginProfile.State = plugin.StateIsSet | plugin.StateIsNull + return nil, nil + } + } + if err != nil { + return nil, err + } + + date := profile.LoginProfile.CreateDate + if date == nil { + return nil, errors.New("login profile doesn't have a createDate") + } + + o, err := CreateResource(a.MqlRuntime, "aws.iam.loginProfile", map[string]*llx.RawData{ + "createDate": llx.TimeData(*date), + }) + if err != nil { + return nil, err + } + return o.(*mqlAwsIamLoginProfile), nil +} + +func (a *mqlAwsIamLoginProfile) init() (string, error) { + date := a.CreateDate.Data + if date == nil { + return "", nil + } + // Note: the precision of AWS logins is in seconds. Current AWS docs don't + // specify a precision. Using seconds is reasonable. + return strconv.FormatInt(date.Unix(), 10), nil +} From 585771067c407bee62731e52334c46a28d6b9731 Mon Sep 17 00:00:00 2001 From: Dominik Richter Date: Fri, 12 Jan 2024 10:34:21 -0800 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=A7=B9=20rename=20createDate=20=3D>?= =?UTF-8?q?=20createdAt=20to=20harmonize?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Dominik Richter --- providers/aws/resources/aws.lr | 4 ++-- providers/aws/resources/aws.lr.go | 14 +++++++------- providers/aws/resources/aws.lr.manifest.yaml | 2 +- providers/aws/resources/aws_iam.go | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/providers/aws/resources/aws.lr b/providers/aws/resources/aws.lr index 6fc86df68d..8f8d55282f 100644 --- a/providers/aws/resources/aws.lr +++ b/providers/aws/resources/aws.lr @@ -782,9 +782,9 @@ private aws.iam.user @defaults("arn name") { } // AWS IAM login profile for a user -private aws.iam.loginProfile @defaults("createDate") { +private aws.iam.loginProfile @defaults("createdAt") { // Time when the login profile was created - createDate time + createdAt time } // AWS IAM policy diff --git a/providers/aws/resources/aws.lr.go b/providers/aws/resources/aws.lr.go index 0c8230fed9..328ad01d09 100644 --- a/providers/aws/resources/aws.lr.go +++ b/providers/aws/resources/aws.lr.go @@ -1552,8 +1552,8 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "aws.iam.user.loginProfile": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsIamUser).GetLoginProfile()).ToDataRes(types.Resource("aws.iam.loginProfile")) }, - "aws.iam.loginProfile.createDate": func(r plugin.Resource) *plugin.DataRes { - return (r.(*mqlAwsIamLoginProfile).GetCreateDate()).ToDataRes(types.Time) + "aws.iam.loginProfile.createdAt": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsIamLoginProfile).GetCreatedAt()).ToDataRes(types.Time) }, "aws.iam.policy.arn": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsIamPolicy).GetArn()).ToDataRes(types.String) @@ -4961,8 +4961,8 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlAwsIamLoginProfile).__id, ok = v.Value.(string) return }, - "aws.iam.loginProfile.createDate": func(r plugin.Resource, v *llx.RawData) (ok bool) { - r.(*mqlAwsIamLoginProfile).CreateDate, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) + "aws.iam.loginProfile.createdAt": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsIamLoginProfile).CreatedAt, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) return }, "aws.iam.policy.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { @@ -12133,7 +12133,7 @@ type mqlAwsIamLoginProfile struct { MqlRuntime *plugin.Runtime __id string // optional: if you define mqlAwsIamLoginProfileInternal it will be used here - CreateDate plugin.TValue[*time.Time] + CreatedAt plugin.TValue[*time.Time] } // createAwsIamLoginProfile creates a new instance of this resource @@ -12168,8 +12168,8 @@ func (c *mqlAwsIamLoginProfile) MqlID() string { return c.__id } -func (c *mqlAwsIamLoginProfile) GetCreateDate() *plugin.TValue[*time.Time] { - return &c.CreateDate +func (c *mqlAwsIamLoginProfile) GetCreatedAt() *plugin.TValue[*time.Time] { + return &c.CreatedAt } // mqlAwsIamPolicy for the aws.iam.policy resource diff --git a/providers/aws/resources/aws.lr.manifest.yaml b/providers/aws/resources/aws.lr.manifest.yaml index 20bb312e44..63ae02f982 100755 --- a/providers/aws/resources/aws.lr.manifest.yaml +++ b/providers/aws/resources/aws.lr.manifest.yaml @@ -1705,7 +1705,7 @@ resources: - aws aws.iam.loginProfile: fields: - createDate: {} + createdAt: {} is_private: true min_mondoo_version: latest platform: diff --git a/providers/aws/resources/aws_iam.go b/providers/aws/resources/aws_iam.go index 5b002025e8..971b01ed1e 100644 --- a/providers/aws/resources/aws_iam.go +++ b/providers/aws/resources/aws_iam.go @@ -1339,7 +1339,7 @@ func (a *mqlAwsIamUser) loginProfile() (*mqlAwsIamLoginProfile, error) { } o, err := CreateResource(a.MqlRuntime, "aws.iam.loginProfile", map[string]*llx.RawData{ - "createDate": llx.TimeData(*date), + "createdAt": llx.TimeData(*date), }) if err != nil { return nil, err @@ -1348,7 +1348,7 @@ func (a *mqlAwsIamUser) loginProfile() (*mqlAwsIamLoginProfile, error) { } func (a *mqlAwsIamLoginProfile) init() (string, error) { - date := a.CreateDate.Data + date := a.CreatedAt.Data if date == nil { return "", nil } From 17403c0923648b145def53eb32796a892c932e87 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sun, 14 Jan 2024 17:29:35 +0100 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Tim Smith --- providers/aws/resources/aws.lr.manifest.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/aws/resources/aws.lr.manifest.yaml b/providers/aws/resources/aws.lr.manifest.yaml index 63ae02f982..e0dcfe8af5 100755 --- a/providers/aws/resources/aws.lr.manifest.yaml +++ b/providers/aws/resources/aws.lr.manifest.yaml @@ -1707,7 +1707,7 @@ resources: fields: createdAt: {} is_private: true - min_mondoo_version: latest + min_mondoo_version: 10.0 platform: name: - aws @@ -1778,7 +1778,7 @@ resources: groups: {} id: {} loginProfile: - min_mondoo_version: latest + min_mondoo_version: 10.0 name: {} passwordLastUsed: {} policies: {}