11

Estoy creando una pila que necesita acceso a un depósito S3 privado para descargar la versión más reciente de mi aplicación. Estoy usando IAM roles, una característica relativamente nueva de AWS que permite a las instancias de EC2 asignar roles específicos, que luego se combinan con las políticas de IAM. Desafortunadamente, estos roles vienen con credenciales de API temporales generados en instanciación. No es paralizante, pero me ha obligado a hacer cosas como esta secuencia de comandos nube-init (simplificado que sólo el bit correspondiente):¿Se pueden usar credenciales temporales de rol de IAM en plantillas de formación de nubes?

#!/bin/sh 

# Grab our credentials from the meta-data and parse the response 
CREDENTIALS=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access) 
S3_ACCESS_KEY=$(echo $CREDENTIALS | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['AccessKeyId'];") 
S3_SECRET_KEY=$(echo $CREDENTIALS | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['SecretAccessKey'];") 
S3_TOKEN=$(echo $CREDENTIALS | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['Token'];") 

# Create an executable script to pull the file 
cat <<EOF> /tmp/pullS3.rb 
require 'rubygems' 
require 'aws-sdk' 
AWS.config(
    :access_key_id  => "$S3_ACCESS_KEY", 
    :secret_access_key => "$S3_SECRET_KEY", 
    :session_token  => "$S3_TOKEN") 
s3 = AWS::S3.new() 
myfile = s3.buckets['mybucket'].objects["path/to/my/file"] 
File.open("/path/to/save/myfile", "w") do |f| 
    f.write(myfile.read) 
end 
EOF 

# Downloading the file 
ruby /tmp/pullS3.rb 

primero y más importante: Esto funciona, y funciona bastante bien. De todos modos, me encantaría utilizar el soporte existente de CloudFormation para el acceso a la fuente. Específicamente, cfn-init admite el uso de authentication resources para obtener datos protegidos, incluidos los segmentos S3. ¿Hay alguna forma de acceder a estas claves desde cfn-init, o quizás vincular el rol de IAM a un recurso de autenticación?

Supongo que una alternativa sería poner mi fuente detrás de otro servicio autenticado, pero esa no es una opción viable en este momento.

Otra ventaja prometedora es la AWS::IAM::AccessKey resource, pero los documentos no sugieren que se pueda usar con roles. Voy a intentarlo de todos modos.

+0

[boto] (http://boto.readthedocs.org/en/ latest /), una popular biblioteca AWS de python, maneja esto de forma elegante. Ver [esta respuesta] (http://stackoverflow.com/a/11130701/877115) para más detalles. – Christopher

Respuesta

11

No estoy seguro de cuándo se agregó la compatibilidad, pero puede usar una función IAM para autenticar descargas S3 para las secciones files y sources en AWS::CloudFormation::Init.

sólo tiene que utilizar roleName en lugar de accessKeyId & secretKey (ver AWS::CloudFormation::Authentication para más detalles), por ejemplo:

"Metadata": { 
    "AWS::CloudFormation::Init": { 
     "download": { 
      "files": { 
       "/tmp/test.txt": { 
        "source": "http://myBucket.s3.amazonaws.com/test.txt" 
       } 
      } 
     } 
    }, 
    "AWS::CloudFormation::Authentication": { 
     "default" : { 
      "type": "s3", 
      "buckets": [ "myBucket" ], 
      "roleName": { "Ref": "myRole" } 
     } 
    } 
} 

probado con aws-cfn-bootstrap-1.3-11

+0

No veo cómo esta es la respuesta. Además, debe adjuntar el rol a la instancia de ec2, que le otorga acceso permanente al depósito. –

1

Me las arreglé para hacer que esto funcione. Lo que utilicé fue código de este intercambio: https://forums.aws.amazon.com/message.jspa?messageID=319465

El código no utiliza las Políticas de IAM: en su lugar, usa AWS :: S3 :: BucketPolicy.

Nube formation código fragmento:

"Resources" : {  

"CfnUser" : { 
    "Type" : "AWS::IAM::User", 
    "Properties" : { 
    "Path": "/", 
    "Policies": [{ 
     "PolicyName": "root", 
     "PolicyDocument": { "Statement":[{ 
     "Effect" : "Allow", 
     "Action" : [ 
      "cloudformation:DescribeStackResource", 
      "s3:GetObject" 
     ], 
     "Resource" :"*" 
     }]} 
    }] 
    } 
}, 

"CfnKeys" : { 
    "Type" : "AWS::IAM::AccessKey", 
    "Properties" : { 
    "UserName" : {"Ref": "CfnUser"} 
    } 
}, 

"BucketPolicy" : { 
    "Type" : "AWS::S3::BucketPolicy", 
    "Properties" : { 
    "PolicyDocument": { 
     "Version"  : "2008-10-17", 
     "Id"   : "CfAccessPolicy", 
     "Statement" : [{ 
     "Sid"  : "ReadAccess", 
     "Action"  : ["s3:GetObject"], 
     "Effect"  : "Allow", 
     "Resource" : { "Fn::Join" : ["", ["arn:aws:s3:::<MY_BUCKET>/*"]]}, 
     "Principal" : { "AWS": {"Fn::GetAtt" : ["CfnUser", "Arn"]} } 
     }] 
    }, 
    "Bucket" : "<MY_BUCKET>" 
    } 
}, 

"WebServer": { 
    "Type": "AWS::EC2::Instance", 
    "DependsOn" : "BucketPolicy", 
    "Metadata" : { 

    "AWS::CloudFormation::Init" : { 
     "config" : { 

     "sources" : { 
      "/etc/<MY_PATH>" : "https://s3.amazonaws.com/<MY_BUCKET>/<MY_FILE>" 
     } 

     } 
    }, 

    "AWS::CloudFormation::Authentication" : { 
     "S3AccessCreds" : { 
     "type" : "S3", 
     "accessKeyId" : { "Ref" : "CfnKeys" }, 
     "secretKey" : {"Fn::GetAtt": ["CfnKeys", "SecretAccessKey"]}, 
     "buckets" : [ "<MY_BUCKET>" ] 
     } 
    } 
    }, 

    "Properties": { 
    "ImageId" : "<MY_INSTANCE_ID>", 
    "InstanceType" : { "Ref" : "WebServerInstanceType" }, 
    "KeyName" : {"Ref": "KeyName"}, 
    "SecurityGroups" : [ "<MY_SECURITY_GROUP>" ], 

    "UserData"  : { "Fn::Base64" : { "Fn::Join" : ["", [ 
     "#!/bin/bash\n", 

     "# Helper function\n", 
     "function error_exit\n", 
     "{\n", 
     " cfn-signal -e 1 -r \"$1\" '", { "Ref" : "WaitHandle" }, "'\n", 
     " exit 1\n", 
     "}\n", 

     "# Install Webserver Packages etc \n", 
     "cfn-init -v --region ", { "Ref" : "AWS::Region" }, 
     " -s ", { "Ref" : "AWS::StackName" }, " -r WebServer ", 
     "   --access-key ", { "Ref" : "CfnKeys" }, 
     "   --secret-key ", {"Fn::GetAtt": ["CfnKeys", "SecretAccessKey"]}, " || error_exit 'Failed to run cfn-init'\n", 

     "# All is well so signal success\n", 
     "cfn-signal -e 0 -r \"Setup complete\" '", { "Ref" : "WaitHandle" }, "'\n" 

    ]]}}   
    } 
} 

Obviamente reemplazando MY_BUCKET, mi_archivo, MY_INSTANCE_ID, MY_SECURITY_GROUP con sus valores.

Cuestiones relacionadas