Как вложить пару KeyValue в метод AddAction AWS CDK PolicyStatement?

В настоящее время я пытаюсь воспроизвести функциональность сценария powershell другого разработчика, используя AWS CDK с приложением .NET. Он создает шаблон CloudFormation (YAML) с помощью VaporShell. Я поместил шаблон CloudFormation ниже (многие имена я сделал общими для этого поста). Я поставил стрелку, указывающую на пару ключ-значение, которая вызывает у меня головную боль.

Resources:
  rSNSTopic:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: 'SNS topic'
      TopicName: 'SNS Topic'
  rSNSPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      Topics:
        - !Ref 'rSNSTopic'
      PolicyDocument:
        Statement:
          - Condition:
              StringEquals:
                AWS:SourceOwner: 'CurrentAcct' <=== This is the key/value pair.
            Action:
              - SNS:Publish
              - SNS:RemovePermission
              - SNS:SetTopicAttributes
              - SNS:DeleteTopic
              - SNS:ListSubscriptionsByTopic
              - SNS:GetTopicAttributes
              - SNS:Receive
              - SNS:AddPermission
              - SNS:Subscribe
            Resource: !Ref 'rSNSTopic'
            Effect: Allow
            Sid: Default
            Principal:
              AWS: '*'
      Version: '2012-10-17'

Мне удалось создать еще один шаблон CloudFormation с помощью приложения C# и AWS CDK. Он работает почти идеально, ЗА ИСКЛЮЧЕНИЕМ создания пары ключ-значение, которую я выделил выше. Я попытался использовать массив, создать новый объект оператора политики и использовать объект пары "ключ/значение" в .NET. Ниже я приведу примеры каждой из этих трех попыток и соответствующий вывод. Кто-нибудь знает способ сгенерировать пару ключ/значение так же, как показано выше? Использование CDK с C#, конечно.

Попытка 1: Использование массива строк.

Код С# (ниже):

var topic = new Topic(this, "rSNSTopic", new TopicProps
        {               
            DisplayName = "SNS topic",
            TopicName = "SNS topic"
        });

        var topicPolicyStatement1 = new PolicyStatement(0)
            .Describe("Default")
            .AddAwsPrincipal("*")
            .AddActions("- SNS:Publish\n" +
                        "- SNS:RemovePermission\n" +
                        "- SNS:SetTopicAttributes\n" +
                        "- SNS:DeleteTopic\n" +
                        "- SNS:ListSubscriptionsByTopic\n" +
                        "- SNS:GetTopicAttributes\n" +
                        "- SNS:Receive\n" +
                        "- SNS:AddPermission\n" +
                        "- SNS:Subscribe\n")
            .AddCondition("StringEquals",
               new [] {"AWS:SourceOwner", "pTestAccnt"}) <=== Using an array as the second .AddCondition parameter.
            .AddCondition("aws:SourceArn", topic.TopicArn)
            .AddResource(topic.TopicArn);

        topic.AddToResourcePolicy(topicPolicyStatement1);
        topic.AddToResourcePolicy(topicPolicyStatement2);

Сгенерированная пара ключ/значение часть шаблона CloudFormation (ниже):

Condition:
   StringEquals:
      - AWS:SourceOwner
      - TestAccnt

Попытка 2: Использование нового объекта оператора политики.

Код С# (ниже):

var topic = new Topic(this, "rSNSTopic", new TopicProps
        {               
            DisplayName = "SNS topic",
            TopicName = "SNS topic"
        });

        var topicPolicyStatement1 = new PolicyStatement(0)
            .Describe("Default")
            .AddAwsPrincipal("*")
            .AddActions("- SNS:Publish\n" +
                        "- SNS:RemovePermission\n" +
                        "- SNS:SetTopicAttributes\n" +
                        "- SNS:DeleteTopic\n" +
                        "- SNS:ListSubscriptionsByTopic\n" +
                        "- SNS:GetTopicAttributes\n" +
                        "- SNS:Receive\n" +
                        "- SNS:AddPermission\n" +
                        "- SNS:Subscribe\n")
            .AddCondition("StringEquals",
               new PolicyStatement(0).AddCondition("AWS:SourceOwner", "pTestAccnt")) <=== Using a policy statement as the second .AddCondition parameter.
            .AddCondition("aws:SourceArn", topic.TopicArn)
            .AddResource(topic.TopicArn);

        topic.AddToResourcePolicy(topicPolicyStatement1);
        topic.AddToResourcePolicy(topicPolicyStatement2);

Сгенерированная пара ключ/значение часть шаблона CloudFormation (ниже):

Condition:
   StringEquals:
      Condition: <=== This solution creates a second condition key which throws an error in AWS CloudFormation.
         AWS:SourceOwner: TestAccnt <=== This key value pair looks correct.

Попытка 3: использование объекта Key/Value из объекта оператора политики .NETnew.

Код С# (ниже):

var topic = new Topic(this, "rSNSTopic", new TopicProps
        {               
            DisplayName = "SNS topic",
            TopicName = "SNS topic"
        });

        var topicPolicyStatement1 = new PolicyStatement(0)
            .Describe("Default")
            .AddAwsPrincipal("*")
            .AddActions("- SNS:Publish\n" +
                        "- SNS:RemovePermission\n" +
                        "- SNS:SetTopicAttributes\n" +
                        "- SNS:DeleteTopic\n" +
                        "- SNS:ListSubscriptionsByTopic\n" +
                        "- SNS:GetTopicAttributes\n" +
                        "- SNS:Receive\n" +
                        "- SNS:AddPermission\n" +
                        "- SNS:Subscribe\n")
            .AddCondition("StringEquals",
               new KeyValuePair<string, string>("AWS:SourceOwner", "pTestAccnt")) <=== Using a policy statement as the second .AddCondition parameter.
            .AddCondition("aws:SourceArn", topic.TopicArn)
            .AddResource(topic.TopicArn);

        topic.AddToResourcePolicy(topicPolicyStatement1);
        topic.AddToResourcePolicy(topicPolicyStatement2);

Этот подход выдает ошибку. Я подозреваю, что это связано со средой выполнения JSII, компилирующей/интерпретирующей объект пары ключ/значение, который я использовал в приложении C#.

Весь вывод из командной строки (ниже):

Unhandled Exception: System.ArgumentException: Could not infer JSII type for .NET type 'KeyValuePair`2'
Parameter name: type
   at Amazon.JSII.Runtime.Services.Converters.FrameworkToJsiiConverter.InferType(IReferenceMap referenceMap, Type type)
   at Amazon.JSII.Runtime.Services.Converters.ValueConverter.ConvertAny(IReferenceMap referenceMap, Object value)
   at Amazon.JSII.Runtime.Services.Converters.ValueConverter.TryConvertPrimitive(IReferenceMap referenceMap, Object value, Boolean isOptional, PrimitiveType primitiveType, Object& result)
   at Amazon.JSII.Runtime.Services.Converters.ValueConverter.TryConvert(TypeReference typeReference, IReferenceMap referenceMap, Object value, Object& result)
   at Amazon.JSII.Runtime.Deputy.DeputyBase.<>c__DisplayClass20_0.<ConvertArguments>b__0(Parameter parameter, Object frameworkArgument)
   at System.Linq.Enumerable.ZipIterator[TFirst,TSecond,TResult](IEnumerable`1 first, IEnumerable`1 second, Func`3 resultSelector)+MoveNext()
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Amazon.JSII.Runtime.Deputy.DeputyBase.<InvokeMethodCore>g__GetResult|18_0[T](<>c__DisplayClass18_0`1& )
   at Amazon.JSII.Runtime.Deputy.DeputyBase.InvokeMethodCore[T](JsiiMethodAttribute methodAttribute, Object[] arguments, Func`3 beginFunc, Func`3 invokeFunc)
   at Amazon.JSII.Runtime.Deputy.DeputyBase.InvokeInstanceMethod[T](Object[] arguments, String methodName)
   at HelloCdk.TestStack..ctor(App parent, String name, IStackProps props) in C:\Users\SomeUser\Documents\git\SomeGITRepo\SingleStackGenerator\src\HelloCdk\TestStack.cs:line 57
   at HelloCdk.Program.Main(String[] args) in C:\Users\SomeUser\Documents\git\SomeGITRepo\SingleStackGenerator\src\HelloCdk\Program.cs:line 18
(node:39548) UnhandledPromiseRejectionWarning: Error: EPIPE: broken pipe, write
    at Object.writeSync (fs.js:569:3)
    at t.SyncStdio.writeBuffer (C:\Users\SomeUser\AppData\Local\Temp\gnh3dhha.5kf\jsii-runtime.js:1:165352)
    at t.SyncStdio.writeLine (C:\Users\SomeUser\AppData\Local\Temp\gnh3dhha.5kf\jsii-runtime.js:1:164892)
    at t.InputOutput.write (C:\Users\SomeUser\AppData\Local\Temp\gnh3dhha.5kf\jsii-runtime.js:1:164341)
    at t.KernelHost.writeError (C:\Users\SomeUser\AppData\Local\Temp\gnh3dhha.5kf\jsii-runtime.js:1:79440)
    at i.then.catch.e (C:\Users\SomeUser\AppData\Local\Temp\gnh3dhha.5kf\jsii-runtime.js:1:79101)
(node:39548) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:39548) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Subprocess exited with error 3762504530
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
1 363
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я придумал решение. Объект "словарь" в C# идеален, и среда выполнения JSII также его компилирует.

Столкнулся с той же проблемой, и решение было не совсем очевидным... Публикация окончательного фрагмента кода:

var topic = new Topic(this, "rSNSTopic", new TopicProps
{
    DisplayName = "SNS topic",
    TopicName = "SNS topic"
});

topic.AddToResourcePolicy(new PolicyStatement(
    new PolicyStatementProps
    {
        Principals = new IPrincipal[] { new AnyPrincipal() },
        Actions = new []
        {
            "SNS:Publish",
            "SNS:RemovePermission",
            "SNS:SetTopicAttributes",
            "SNS:DeleteTopic",
            "SNS:ListSubscriptionsByTopic",
            "SNS:GetTopicAttributes",
            "SNS:Receive",
            "SNS:AddPermission",
            "SNS:Subscribe"
        },
        Resources = new[] { topic.TopicArn },
        Conditions = new Dictionary<string, object>
        {
            {"StringEquals", 
                new Dictionary<string, object> {{ "aws:SourceOwner", "pTestAccnt" } }},
            {"StringEquals", 
                new Dictionary<string, object> {{ "aws:SourceArn", topic.TopicArn } }
        }
    }
);

Другие вопросы по теме