Comment puis-je éviter l'erreur « Impossible de valider les configurations de destination suivantes » dans AWS CloudFormation ?

Date de la dernière mise à jour : 09/09/2020

J'abonne une rubrique Amazon Simple Notification Service (Amazon SNS) ou une fonction AWS Lambda à des notifications d'événements Amazon Simple Storage Service (Amazon S3). Pourquoi l'erreur « Unable to validate the following destination configurations » (Impossible de valider les configurations de destination suivantes) est-elle générée ? Lorsque j'essaie de définir une dépendance sur la stratégie de rubrique SNS à partir du compartiment S3 de mon modèle, je reçois une erreur de validation de dépendance circulaire.

Brève description

En raison de la façon dont AWS CloudFormation gère l'ordre des dépendances, les notifications d'événements Amazon S3 sont définies comme un attribut du compartiment S3. Ces notifications sont établies lorsque la ressource de compartiment S3 est créée.

Pour éviter une erreur, vous devez créer des ressources dans l'ordre suivant :

  1. Créez la rubrique SNS, car le compartiment S3 fait référence à la rubrique SNS.
  2. Créez le compartiment S3, car la politique de rubrique SNS fait référence au compartiment S3 et à la rubrique SNS.

Avant d'abonner une rubrique SNS aux notifications d'événements S3, vous devez spécifier une politique de rubrique (AWS::SNS::TopicPolicy) avec les autorisations appropriées. L'existence de cette stratégie de rubrique est un préalable à la création de l'abonnement.

Essayez l'une des stratégies suivantes pour éviter l'erreur « Impossible de valider les configurations de destination suivantes » :

  • Spécifier une valeur pour BucketName dans votre modèle AWS CloudFormation
  • Créer une pile, puis la mettre à jour

Résolution

Spécifier une valeur pour BucketName dans votre modèle AWS CloudFormation

Utilisez un nom statique pour votre compartiment S3 en spécifiant une valeur pour la propriété BucketName dans la ressource S3Bucket de votre modèle AWS CloudFormation. Cela évite d'avoir à inclure {"Ref": "paramBucketName"} dans la politique de rubrique SNS et supprime la dépendance intrinsèque entre la politique de rubrique SNS et Amazon S3.

L'exemple de modèle AWS CloudFormation suivant spécifie une valeur codée en dur (-Bucket-Name) pour la propriété BucketName. Dans votre modèle, remplacez toutes les instances de -Bucket-Name par le nom de votre compartiment.

{
  "Resources": {
    "SNSTopic": {
        "Type": "AWS::SNS::Topic"
    },
    "SNSTopicPolicy": {
        "Type": "AWS::SNS::TopicPolicy",
        "Properties": {
            "PolicyDocument": {
                "Id": "MyTopicPolicy",
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "Statement-id",
                        "Effect": "Allow",
                        "Principal": { "Service": "s3.amazonaws.com" },
                        "Action": "sns:Publish",
                        "Resource": { "Ref": "SNSTopic" },
                        "Condition": {
                            "ArnLike": {
                                "aws:SourceArn": { "Fn::Join": [ "", [ "arn:aws:s3:::", "-Bucket-Name-" ]]} }
                        }
                    }
                ]
            },
            "Topics": [ { "Ref": "SNSTopic" } ]
        }
    },
    "S3Bucket": {
        "Type": "AWS::S3::Bucket",
        "DependsOn": ["SNSTopicPolicy"],
        "Properties": {
            "AccessControl": "BucketOwnerFullControl",
            "BucketName": "-Bucket-Name-",
            "NotificationConfiguration": {
                "TopicConfigurations": [
                    {
                        "Topic": { "Ref": "SNSTopic" },
                        "Event": "s3:ObjectCreated:Put"
                    }
                ]
            }
        }
    }
  }
}

Remarque : la ressource S3Bucket a une valeur DependsOn explicite définie sur SNSTopicPolicy. Cet attribut spécifie que le modèle crée la ressource SNSTopicPolicy avant la ressource S3Bucket.

Pour utiliser le même modèle AWS CloudFormation pour les compartiments S3 avec des noms différents, définissez un paramètre pour le nom du compartiment. Le paramètre vous permet d'utiliser le même modèle pour différents noms de compartiment en transmettant le nom du compartiment comme paramètre lors de la création de la pile.

Pour utiliser l'exemple de modèle suivant, vous devez transmettre le nom du compartiment en tant que paramètre paramBucketName lors de la création de la pile.

{
  "Parameters": {
    "paramBucketName": {
      "Type": "String",
      "Description": "Bucket Name"
    }
  },
  "Resources": {
    "SNSTopic": {
        "Type": "AWS::SNS::Topic"
    },
    "SNSTopicPolicy": {
        "Type": "AWS::SNS::TopicPolicy",
        "Properties": {
            "PolicyDocument": {
                "Id": "MyTopicPolicy",
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "Statement-id",
                        "Effect": "Allow",
                        "Principal": { "Service": "s3.amazonaws.com" },
                        "Action": "sns:Publish",
                        "Resource": { "Ref": "SNSTopic" },
                        "Condition": {
                            "ArnLike": {
                                "aws:SourceArn": { "Fn::Join": [ "", [ "arn:aws:s3:::", {"Ref": "paramBucketName"} ]]} }
                        }
                    }
                ]
            },
            "Topics": [ { "Ref": "SNSTopic" } ]
        }
    },
    "S3Bucket": {
        "Type": "AWS::S3::Bucket",
        "DependsOn": ["SNSTopicPolicy"],
        "Properties": {
            "AccessControl": "BucketOwnerFullControl",
            "BucketName": {"Ref": "paramBucketName"},
            "NotificationConfiguration": {
                "TopicConfigurations": [
                    {
                        "Topic": { "Ref": "SNSTopic" },
                        "Event": "s3:ObjectCreated:Put"
                    }
                ]
            }
        }
    }
  }
}

Créer une pile, puis la mettre à jour

Divisez la création de la pile en deux étapes. Tout d'abord, créez la pile sans spécifier la propriété NotificationConfiguration dans la ressource S3Bucket. Ensuite, mettez à jour la pile pour ajouter la notification d'événement S3. Cela évite de définir la notification d'événement S3 avant la création de la politique de rubrique SNS.

1.    Créez toutes les ressources, y compris la stratégie de rubrique SNS. Par exemple :

{
    "Resources": {
        "SNSTopic": {
            "Type": "AWS::SNS::Topic"
        },
        "SNSTopicPolicy": {
            "Type": "AWS::SNS::TopicPolicy",
            "Properties": {
                "PolicyDocument": {
                    "Id": "MyTopicPolicy",
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Sid": "Statement-id",
                            "Effect": "Allow",
                            "Principal": { "Service": "s3.amazonaws.com" },
                            "Action": "sns:Publish",
                            "Resource": { "Ref": "SNSTopic" },
                            "Condition": {
                                "ArnLike": {
                                    "aws:SourceArn": { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3Bucket" } ] ]
                                    }
                                }
                            }
                        }
                    ]
                },
                "Topics": [ { "Ref": "SNSTopic" } ]
            }
        },
        "S3Bucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
                "AccessControl": "BucketOwnerFullControl"
            }
        }
    }
}

2.    Mettez à jour la pile pour ajouter la notification d'événements S3. Par exemple :

{
  "Resources": {
        "SNSTopic": {
        "Type": "AWS::SNS::Topic"
    },
    "SNSTopicPolicy": {
        "Type": "AWS::SNS::TopicPolicy",
        "Properties": {
            "PolicyDocument": {
                "Id": "MyTopicPolicy",
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "Statement-id",
                        "Effect": "Allow",
                        "Principal": { "Service": "s3.amazonaws.com" },
                        "Action": "sns:Publish",
                        "Resource": { "Ref": "SNSTopic" },
                        "Condition": {
                            "ArnLike": {
                                "aws:SourceArn": { "Fn::Join": [ "", [ "arn:aws:s3:::", { "Ref": "S3Bucket" } ] ]
                                }
                            }
                        }
                    }
                ]
            },
            "Topics": [ { "Ref": "SNSTopic" } ]
        }
    },
    "S3Bucket": {
        "Type": "AWS::S3::Bucket",
        "Properties": {
            "AccessControl": "BucketOwnerFullControl",
            "NotificationConfiguration": {
                "TopicConfigurations": [
                    {
                        "Topic": { "Ref": "SNSTopic" },
                        "Event": "s3:ObjectCreated:Put"
                    }
                ]
            }
        }
    }
  }
}

Remarque : vous pouvez utiliser AWS CloudFormation Template Flip pour convertir vos modèles AWS CloudFormation entre les formats JSON et YAML.