Listener su porta 443 con errore 503 in caso di non riscontro tra le regole<\/li><\/ul><\/li><\/ul>\n\n\n\nVPC<\/h2>\n\n\n\n La VPC \u00e8 composta da 9 subnet<\/strong>, 3 per ogni Avaliability Zone, in maniera tale da rendere l\u2019infrastruttura altamente disponibile. Le subnet sono suddivise in:<\/p>\n\n\n\nPUBBLICHE, utilizzate per tutti i servizi che devono essere raggiunti dall\u2019esterno (come l\u2019ALB) o se si vuole esporre direttamente un\u2019istanza EC2 su internet assegnandole un indirizzo IP pubblico dedicato.<\/li> NATTATE, utilizzate per tutti i servizi che necessitano di accedere ad internet, ma che non devono essere raggiunti dall\u2019esterno; come suggerito dal nome, le istanze che verranno create all\u2019interno di queste subnet potranno accedere ad internet tramite dei NAT gateway che risiedono nelle relative subnet pubbliche. Nel nostro caso, abbiamo scelto di optare per le 3 istanze (una per AZ) solo per la VPC di produzione, mentre per gli altri ambienti manterremo una sola istanza.<\/li> PRIVATE, utilizzate per tutti i servizi che non necessitano di accesso ad internet come database RDS.<\/li><\/ul>\n\n\n\nIl costrutto VPC che ci mette a disposizione AWS CDK ha una gestione dei CIDR assegnati alle subnet che rende impossibile effettuare supernetting, privandoci quindi della possibilit\u00e0 di raggruppare le subnet con netmask piu piccole. Abbiamo quindi deciso di utilizzare questo costrutto, assicurandoci per\u00f2 di sovrascrivere i vari CIDR prima del deploy tramite questa porzione di codice:<\/p>\n\n\n\n
myVpc.privateSubnets.forEach((subnet, index) => {\nlet cidr = `${startSubnetsCidr}.${firstPrivateCidr + index}.${endSubnetsCidr}`\nconst cfnSubnet = subnet.node.defaultChild as aws_ec2.CfnSubnet;\ncfnSubnet.addPropertyOverride('CidrBlock', `${cidr}`);\nlet name = `${configFile.projectName}-${process.env.ENVIRONMENT}-natted-${subnet.availabilityZone.replace(\/^\\w+\\-\\w+\\-\\d\/,'')}`;\nlet subName = `Subnet-Natted-${subnet.availabilityZone.replace(\/^\\w+\\-\\w+\\-\\d\/,'').toUpperCase()}-${process.env.ENVIRONMENT}-Name`;\nlet subId = `Subnet-Natted-${subnet.availabilityZone.replace(\/^\\w+\\-\\w+\\-\\d\/,'').toUpperCase()}-${process.env.ENVIRONMENT}-ID`;\nlet subCidr = `Subnet-Natted-${subnet.availabilityZone.replace(\/^\\w+\\-\\w+\\-\\d\/,'').toUpperCase()}-${process.env.ENVIRONMENT}-CIDR`;\ncdk.Aspects.of(subnet).add(\nnew cdk.Tag(\n'Name',\nName\n)\n)\n})<\/code><\/pre>\n\n\n\nRilasciata la VPC possiamo deployare al suo interno tutte le risorse necessarie per far funzionare la vending machine come ad esempio gli Application Load Balancer<\/strong> nelle subnet pubbliche, i Web Server<\/strong> nelle subnet nattate, e i database<\/strong> dedicati ai Web Server nelle subnet private. <\/p>\n\n\n\nAffronteremo, nel prossimo articolo, la creazione di queste risorse.<\/p>\n\n\n\n
Bucket Amazon S3<\/h2>\n\n\n\n Il bucket S3 creato da questo stack viene utilizzato per stoccare i log, gli artifact e il risultato dei git push su GitLab; vengono inoltre assegnati relativi permessi per i ruoli IAM garantendo full access al bucket, e vengono create le removal policy per i log stoccati:<\/p>\n\n\n\n
const myLifeCycleLogsRule: aws_s3.LifecycleRule = {\n\tid: `logs-cleared`,\nenabled: true,\nprefix: `*-${process.env.ENVIRONMENT}-log`,\nexpiration: cdk.Duration.days(1)\n}<\/code><\/pre>\n\n\n\nPer poter utilizzare il bucket S3 come sorgente della pipeline occorre attivare il servizio CloudTrail<\/strong> per garantire la possibilit\u00e0 di intercettare gli eventi:<\/p>\n\n\n\nconst myTrail = new aws_cloudtrail.Trail(this, `CloudTrail-${process.env.ENVIRONMENT}`, {\ntrailName: `trail-${process.env.ENVIRONMENT}`,\nsendToCloudWatchLogs: true,\nbucket: myGlobalBucketS3,\nencryptionKey: myKms,\ncloudWatchLogGroup: new aws_logs.LogGroup(this, `Logs-${upperEnvironment}`, {\nlogGroupName: `logs-${process.env.ENVIRONMENT}`,\nretention: aws_logs.RetentionDays.THREE_DAYS,\nremovalPolicy: RemovalPolicy.DESTROY\n}),\ncloudWatchLogsRetention: aws_logs.RetentionDays.THREE_DAYS,\ns3KeyPrefix: `logs-${process.env.ENVIRONMENT}`,\nisMultiRegionTrail: false\n});<\/code><\/pre>\n\n\n\nMa questo non basta. Per far s\u00ec che la pipeline venga invocata all’inserimento di un nuovo file all\u2019interno del bucket S3 \u00e8 necessario configurare un evento di notifica<\/strong> su CloudTrail che stia in ascolto di operazioni di scrittura all\u2019interno bucket S3:<\/p>\n\n\n\nmyTrail.addS3EventSelector([{\n\tbucket: myGlobalBucketS3,\n\tobjectPrefix: `software\/`,\n\t}], {\n\treadWriteType: aws_cloudtrail.ReadWriteType.WRITE_ONLY,\n})\nmyTrail.addS3EventSelector([{\n\tbucket: myGlobalBucketS3,\n\tobjectPrefix: `infrastructure\/`,\n\t}], {\n\treadWriteType: aws_cloudtrail.ReadWriteType.WRITE_ONLY,\n})<\/code><\/pre>\n\n\n\nKMS Key<\/h2>\n\n\n\n Per garantire la cifratura dei dati su S3, su CloudTrail, e nel database, abbiamo creato una chiave KMS customer managed<\/strong>. A questa chiave abbiamo successivamente assegnato una policy che permette alle entit\u00e0 che devono operare sui servizi cifrati di poterla utilizzare:<\/p>\n\n\n\nmyKms.addToResourcePolicy( new iam.PolicyStatement({\nsid: \"Allow principals in the account to decrypt log files\",\nactions: [\n\"kms:Decrypt\",\n\"kms:ReEncryptFrom\"\n],\nprincipals: [ new iam.AccountPrincipal(`${process.env.CDK_DEFAULT_ACCOUNT}`) ],\nresources: [\n`arn:aws:kms:${process.env.CDK_DEFAULT_REGION}:${process.env.CDK_DEFAULT_ACCOUNT}:key\/*`,\n],\nconditions: {\n\"StringLike\": {\n\"kms:EncryptionContext:aws:cloudtrail:arn\": \"arn:aws:cloudtrail:*:*:trail\/*\"\n},\n\"StringEquals\": {\n\"kms:CallerAccount\": `${process.env.CDK_DEFAULT_ACCOUNT}`\n}\n}\n}));<\/code><\/pre>\n\n\n\nApplication Load Balancer<\/h2>\n\n\n\n Questo ALB gestir\u00e0 gli accessi ai nostri servizi indirizzandoli in automatico dalla porta 80 in HTTP alla porta 443 in HTTPS:<\/p>\n\n\n\n
myAppLoadBalancer.addListener(`App-80-Listener`, {\nport: 80,\ndefaultAction: elbv2.ListenerAction.redirect({\npermanent: true,\nport: '443',\nprotocol: 'HTTPS',\n})\n})\nmyAppLoadBalancer.addListener(`App-443-Listener`, {\nport: 443,\ndefaultAction: elbv2.ListenerAction.fixedResponse(503, {\ncontentType: `text\/plain`,\nmessageBody: 'host not found',\n})\n})<\/code><\/pre>\n\n\n\nPer porter gestire le richieste effettuate in https sulla porta 443 \u00e8 necessario che sia associato al relativo listener un certificato facilmente configurabile tramite il servizio AWS Certificate Manager, che oltre alla creazione dei certificati permette anche l\u2019aggiornamento automatico degli stessi. <\/p>\n\n\n\n
Conclusione<\/h2>\n\n\n\n Le risorse configurate all\u2019interno di questo repository costituiscono le fondamenta per l\u2019intera soluzione. <\/p>\n\n\n\n
Nella prossima puntata analizzeremo lo stack applicativo dedicato a ciascun cliente che utilizza i servizi che abbiamo visto oggi. <\/p>\n\n\n\n
Per avere una soluzione solida dal punto di vista di sicurezza e scalabilit\u00e0 \u00e8 necessario che ci\u00f2 che la mantiene in piedi sia altrettanto affidabile: per questo motivo ci siamo appoggiati unicamente a servizi gestiti da AWS, riducendo quindi l\u2019effort di amministrazione e monitoring.<\/p>\n\n\n\n
Ci vediamo tra 14 giorni per l’ultimo capitolo! <\/p>\n\n\n\n
\n\n\n\nAbout Proud2beCloud<\/h4>\n\n\n\n Proud2beCloud \u00e8 il blog di beSharp<\/a>, APN Premier Consulting Partner italiano esperto nella progettazione, implementazione e gestione di infrastrutture Cloud complesse e servizi AWS avanzati. Prima di essere scrittori, siamo Solutions Architect che, dal 2007, lavorano quotidianamente con i servizi AWS. Siamo innovatori alla costante ricerca della soluzione pi\u00f9 all’avanguardia per noi e per i nostri clienti. Su Proud2beCloud condividiamo regolarmente i nostri migliori spunti con chi come noi, per lavoro o per passione, lavora con il Cloud di AWS. Partecipa alla discussione!<\/p>\n","protected":false},"excerpt":{"rendered":"Bentornati nella nostra mini-serie dedicata al Platform-as-a-Services su AWS. Nella prima parte, abbiamo percorso i punti chiave di una implementazione […]<\/p>\n","protected":false},"author":24,"featured_media":5023,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[241],"tags":[315,537,251,291,293,285,364,360,600,602,604],"class_list":["post-5017","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-amazon-ec2","tag-amazon-rds-it","tag-amazon-s3","tag-aws-codebuild","tag-aws-codedeploy","tag-aws-codepipeline","tag-ci-cd","tag-continuous-delivery","tag-gitlab-it","tag-platform-as-a-service-paas-it","tag-virtual-host-it"],"yoast_head":"\n
PaaS su AWS: come implementarlo nel modo migliore - Parte II - Proud2beCloud Blog<\/title>\n \n \n \n \n \n \n \n \n \n \n \n \n\t \n\t \n\t \n \n \n \n \n \n \n\t \n\t \n\t \n