From: Casey Bodley Date: Thu, 1 Feb 2024 19:58:22 +0000 (-0500) Subject: rgw/iam: add get_managed_policy() factory function X-Git-Tag: v19.1.0~99^2~81 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=5e86656d7f2caefb68e41fa13e5ba4aa730ed7e5;p=ceph.git rgw/iam: add get_managed_policy() factory function add definitions for the following managed policy ARNs: * arn:aws:iam::aws:policy/IAMFullAccess * arn:aws:iam::aws:policy/IAMReadOnlyAccess * arn:aws:iam::aws:policy/AmazonSNSFullAccess * arn:aws:iam::aws:policy/AmazonSNSReadOnlyAccess * arn:aws:iam::aws:policy/AmazonS3FullAccess * arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess factory function get_managed_policy() returns a parsed Policy for the requested ARN if available Signed-off-by: Casey Bodley (cherry picked from commit ccb6c38d8ea28d337430efc6e660b24896e75f17) --- diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index 499fb61c0fe6a..ca7bf2b104fc8 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -130,6 +130,7 @@ set(librgw_common_srcs rgw_crypt.cc rgw_crypt_sanitize.cc rgw_iam_policy.cc + rgw_iam_managed_policy.cc rgw_rest_user_policy.cc rgw_zone.cc rgw_sts.cc diff --git a/src/rgw/rgw_iam_managed_policy.cc b/src/rgw/rgw_iam_managed_policy.cc new file mode 100644 index 0000000000000..3034832b2032a --- /dev/null +++ b/src/rgw/rgw_iam_managed_policy.cc @@ -0,0 +1,177 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright contributors to the Ceph project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "rgw_iam_managed_policy.h" +#include "rgw_iam_policy.h" + +namespace rgw::IAM { + +// Type: AWS managed policy +// Creation time: February 06, 2015, 18:40 UTC +// Edited time: June 21, 2019, 19:40 UTC +// ARN: arn:aws:iam::aws:policy/IAMFullAccess +// Policy version: v2 (default) +static constexpr std::string_view IAMFullAccess = R"( +{ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Action" : [ + "iam:*", + "organizations:DescribeAccount", + "organizations:DescribeOrganization", + "organizations:DescribeOrganizationalUnit", + "organizations:DescribePolicy", + "organizations:ListChildren", + "organizations:ListParents", + "organizations:ListPoliciesForTarget", + "organizations:ListRoots", + "organizations:ListPolicies", + "organizations:ListTargetsForPolicy" + ], + "Resource" : "*" + } + ] +})"; + +// Type: AWS managed policy +// Creation time: February 06, 2015, 18:40 UTC +// Edited time: January 25, 2018, 19:11 UTC +// ARN: arn:aws:iam::aws:policy/IAMReadOnlyAccess +// Policy version: v4 (default) +static constexpr std::string_view IAMReadOnlyAccess = R"( +{ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Action" : [ + "iam:GenerateCredentialReport", + "iam:GenerateServiceLastAccessedDetails", + "iam:Get*", + "iam:List*", + "iam:SimulateCustomPolicy", + "iam:SimulatePrincipalPolicy" + ], + "Resource" : "*" + } + ] +})"; + +// Type: AWS managed policy +// Creation time: February 06, 2015, 18:41 UTC +// Edited time: February 06, 2015, 18:41 UTC +// ARN: arn:aws:iam::aws:policy/AmazonSNSFullAccess +// Policy version: v1 (default) +static constexpr std::string_view AmazonSNSFullAccess = R"( +{ + "Version" : "2012-10-17", + "Statement" : [ + { + "Action" : [ + "sns:*" + ], + "Effect" : "Allow", + "Resource" : "*" + } + ] +})"; + +// Type: AWS managed policy +// Creation time: February 06, 2015, 18:41 UTC +// Edited time: February 06, 2015, 18:41 UTC +// ARN: arn:aws:iam::aws:policy/AmazonSNSReadOnlyAccess +// Policy version: v1 (default) +static constexpr std::string_view AmazonSNSReadOnlyAccess = R"( +{ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Action" : [ + "sns:GetTopicAttributes", + "sns:List*" + ], + "Resource" : "*" + } + ] +})"; + +// Type: AWS managed policy +// Creation time: February 06, 2015, 18:40 UTC +// Edited time: September 27, 2021, 20:16 UTC +// ARN: arn:aws:iam::aws:policy/AmazonS3FullAccess +// Policy version: v2 (default) +static constexpr std::string_view AmazonS3FullAccess = R"( +{ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Action" : [ + "s3:*", + "s3-object-lambda:*" + ], + "Resource" : "*" + } + ] +})"; + +// Type: AWS managed policy +// Creation time: February 06, 2015, 18:40 UTC +// Edited time: August 10, 2023, 21:31 UTC +// ARN: arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess +// Policy version: v3 (default) +static constexpr std::string_view AmazonS3ReadOnlyAccess = R"( +{ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Action" : [ + "s3:Get*", + "s3:List*", + "s3:Describe*", + "s3-object-lambda:Get*", + "s3-object-lambda:List*" + ], + "Resource" : "*" + } + ] +})"; + +auto get_managed_policy(CephContext* cct, std::string_view arn) + -> std::optional +{ + const std::string tenant; // empty tenant + constexpr bool reject = false; // reject_invalid_principals + if (arn == "arn:aws:iam::aws:policy/IAMFullAccess") { + return Policy{cct, tenant, std::string{IAMFullAccess}, reject}; + } else if (arn == "arn:aws:iam::aws:policy/IAMReadOnlyAccess") { + return Policy{cct, tenant, std::string{IAMReadOnlyAccess}, reject}; + } else if (arn == "arn:aws:iam::aws:policy/AmazonSNSFullAccess") { + return Policy{cct, tenant, std::string{AmazonSNSFullAccess}, reject}; + } else if (arn == "arn:aws:iam::aws:policy/AmazonSNSReadOnlyAccess") { + return Policy{cct, tenant, std::string{AmazonSNSReadOnlyAccess}, reject}; + } else if (arn == "arn:aws:iam::aws:policy/AmazonS3FullAccess") { + return Policy{cct, tenant, std::string{AmazonS3FullAccess}, reject}; + } else if (arn == "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess") { + return Policy{cct, tenant, std::string{AmazonS3ReadOnlyAccess}, reject}; + } + return {}; +} + +} // namespace rgw::IAM diff --git a/src/rgw/rgw_iam_managed_policy.h b/src/rgw/rgw_iam_managed_policy.h new file mode 100644 index 0000000000000..35a5cef73df9c --- /dev/null +++ b/src/rgw/rgw_iam_managed_policy.h @@ -0,0 +1,30 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright contributors to the Ceph project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include +#include +#include "common/ceph_context.h" + +namespace rgw::IAM { + +struct Policy; + +/// Return a managed policy by ARN. +auto get_managed_policy(CephContext* cct, std::string_view arn) + -> std::optional; + +} // namespace rgw::IAM diff --git a/src/test/rgw/test_rgw_iam_policy.cc b/src/test/rgw/test_rgw_iam_policy.cc index 241263be749bd..3ecbb782e5ce5 100644 --- a/src/test/rgw/test_rgw_iam_policy.cc +++ b/src/test/rgw/test_rgw_iam_policy.cc @@ -12,6 +12,8 @@ * */ +#include "rgw_iam_policy.h" + #include #include @@ -26,7 +28,7 @@ #include "global/global_init.h" #include "rgw_auth.h" #include "rgw_auth_registry.h" -#include "rgw_iam_policy.h" +#include "rgw_iam_managed_policy.h" #include "rgw_op.h" #include "rgw_process_env.h" #include "rgw_sal_rados.h" @@ -128,6 +130,8 @@ using rgw::IAM::snsAllValue; using rgw::IAM::organizationsAllValue; using rgw::IAM::allValue; +using rgw::IAM::get_managed_policy; + class FakeIdentity : public Identity { const Principal id; public: @@ -762,6 +766,139 @@ TEST_F(PolicyTest, Eval7) { Effect::Pass); } + +class ManagedPolicyTest : public ::testing::Test { +protected: + intrusive_ptr cct; +public: + ManagedPolicyTest() : cct(new CephContext(CEPH_ENTITY_TYPE_CLIENT)) {} +}; + +TEST_F(ManagedPolicyTest, IAMFullAccess) +{ + auto p = get_managed_policy(cct.get(), "arn:aws:iam::aws:policy/IAMFullAccess"); + ASSERT_TRUE(p); + + Action_t act = iamAllValue | organizationsAllValue; + act[iamAll] = 1; + act[organizationsAll] = 1; + EXPECT_EQ(act, p->statements[0].action); +} + +TEST_F(ManagedPolicyTest, IAMReadOnlyAccess) +{ + auto p = get_managed_policy(cct.get(), "arn:aws:iam::aws:policy/IAMReadOnlyAccess"); + ASSERT_TRUE(p); + + Action_t act; + act[iamGenerateCredentialReport] = 1; + act[iamGenerateServiceLastAccessedDetails] = 1; + act[iamGetUserPolicy] = 1; + act[iamGetRole] = 1; + act[iamGetRolePolicy] = 1; + act[iamGetOIDCProvider] = 1; + act[iamGetUser] = 1; + act[iamListUserPolicies] = 1; + act[iamListRoles] = 1; + act[iamListRolePolicies] = 1; + act[iamListOIDCProviders] = 1; + act[iamListRoleTags] = 1; + act[iamListUsers] = 1; + act[iamListAccessKeys] = 1; + act[iamSimulateCustomPolicy] = 1; + act[iamSimulatePrincipalPolicy] = 1; + + EXPECT_EQ(act, p->statements[0].action); +} + +TEST_F(ManagedPolicyTest, AmazonSNSFullAccess) +{ + auto p = get_managed_policy(cct.get(), "arn:aws:iam::aws:policy/AmazonSNSFullAccess"); + ASSERT_TRUE(p); + + Action_t act = snsAllValue; + act[snsAll] = 1; + EXPECT_EQ(act, p->statements[0].action); +} + +TEST_F(ManagedPolicyTest, AmazonSNSReadOnlyAccess) +{ + auto p = get_managed_policy(cct.get(), "arn:aws:iam::aws:policy/AmazonSNSReadOnlyAccess"); + ASSERT_TRUE(p); + + Action_t act; + // sns:GetTopicAttributes + act[snsGetTopicAttributes] = 1; + // sns:List* + act[snsListTopics] = 1; + + EXPECT_EQ(act, p->statements[0].action); +} + +TEST_F(ManagedPolicyTest, AmazonS3FullAccess) +{ + auto p = get_managed_policy(cct.get(), "arn:aws:iam::aws:policy/AmazonS3FullAccess"); + ASSERT_TRUE(p); + + Action_t act = s3AllValue | s3objectlambdaAllValue; + act[s3All] = 1; + act[s3objectlambdaAll] = 1; + EXPECT_EQ(act, p->statements[0].action); +} + +TEST_F(ManagedPolicyTest, AmazonS3ReadOnlyAccess) +{ + auto p = get_managed_policy(cct.get(), "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"); + ASSERT_TRUE(p); + + Action_t act; + // s3:Get* + act[s3GetObject] = 1; + act[s3GetObjectVersion] = 1; + act[s3GetObjectAcl] = 1; + act[s3GetObjectVersionAcl] = 1; + act[s3GetObjectTorrent] = 1; + act[s3GetObjectVersionTorrent] = 1; + act[s3GetAccelerateConfiguration] = 1; + act[s3GetBucketAcl] = 1; + act[s3GetBucketOwnershipControls] = 1; + act[s3GetBucketCORS] = 1; + act[s3GetBucketVersioning] = 1; + act[s3GetBucketRequestPayment] = 1; + act[s3GetBucketLocation] = 1; + act[s3GetBucketPolicy] = 1; + act[s3GetBucketNotification] = 1; + act[s3GetBucketLogging] = 1; + act[s3GetBucketTagging] = 1; + act[s3GetBucketWebsite] = 1; + act[s3GetLifecycleConfiguration] = 1; + act[s3GetReplicationConfiguration] = 1; + act[s3GetObjectTagging] = 1; + act[s3GetObjectVersionTagging] = 1; + act[s3GetBucketObjectLockConfiguration] = 1; + act[s3GetObjectRetention] = 1; + act[s3GetObjectLegalHold] = 1; + act[s3GetBucketPolicyStatus] = 1; + act[s3GetPublicAccessBlock] = 1; + act[s3GetBucketPublicAccessBlock] = 1; + act[s3GetBucketEncryption] = 1; + // s3:List* + act[s3ListMultipartUploadParts] = 1; + act[s3ListBucket] = 1; + act[s3ListBucketVersions] = 1; + act[s3ListAllMyBuckets] = 1; + act[s3ListBucketMultipartUploads] = 1; + // s3:Describe* + act[s3DescribeJob] = 1; + // s3-object-lambda:Get* + act[s3objectlambdaGetObject] = 1; + // s3-object-lambda:List* + act[s3objectlambdaListBucket] = 1; + act[s3objectlambdaAll] = 1; + + EXPECT_EQ(act, p->statements[0].action); +} + const string PolicyTest::arbitrary_tenant = "arbitrary_tenant"; string PolicyTest::example1 = R"( {