Skip to content

Commit 5e1f142

Browse files
authored
Merge pull request #903 from NHSDigital/feature/jale13-nrl-1385-set-up-powerbi-gateway
NRL 1385 Set up EC2 for automated data refresh
2 parents 134abce + 2b1e371 commit 5e1f142

File tree

16 files changed

+424
-0
lines changed

16 files changed

+424
-0
lines changed

terraform/account-wide-infrastructure/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,20 @@ $ terraform apply \
124124
125125
Replacing AWS_ACCOUNT_ID with the AWS account number of your account.
126126
127+
### Reporting Resources
128+
129+
If deploying the EC2 set up to a new environment, these steps need to be followed:
130+
131+
1. Run the below CLI command, and RDP into the newly created EC2 instance (localhost:13389)
132+
133+
```
134+
aws ssm start-session --target <AMI> --document-name AWS-StartPortForwardingSession --parameters "localPortNumber=13389,portNumber=3389"
135+
```
136+
137+
2. Install Athena ODBC driver and Power BI personal on premises gateway
138+
3. Configure ODBC driver to connect to relevant Athena instance and log in to the gateway using NHS email
139+
4. Log into power bi and test the refresh on the relevant data sources
140+
127141
## Tear down account wide resources
128142
129143
WARNING - This action will destroy all account-wide resources from the AWS account. This should
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module "vpc" {
2+
source = "../modules/vpc"
3+
vpc_cidr_block = var.vpc_cidr_block
4+
enable_dns_hostnames = var.enable_dns_hostnames
5+
vpc_public_subnets_cidr_block = var.vpc_public_subnets_cidr_block
6+
vpc_private_subnets_cidr_block = var.vpc_private_subnets_cidr_block
7+
aws_azs = var.aws_azs
8+
name_prefix = "nhsd-nrlf--dev"
9+
}
10+
11+
module "powerbi_gw_instance_v2" {
12+
source = "../modules/ec2"
13+
use_custom_ami = true
14+
instance_type = var.instance_type
15+
name_prefix = "nhsd-nrlf--dev-powerbi-gw-v2"
16+
target_bucket_arn = module.dev-glue.target_bucket_arn
17+
glue_kms_key_arn = module.dev-glue.aws_kms_key_arn
18+
athena_kms_key_arn = module.dev-athena.kms_key_arn
19+
athena_bucket_arn = module.dev-athena.bucket_arn
20+
21+
subnet_id = module.vpc.private_subnet_id
22+
security_groups = [module.vpc.powerbi_gw_security_group_id]
23+
}

terraform/account-wide-infrastructure/dev/vars.tf

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,45 @@ variable "devsandbox_api_domain_name" {
1313
description = "The internal DNS name of the API Gateway for the dev sandbox environment"
1414
default = "dev-sandbox.api.record-locator.dev.national.nhs.uk"
1515
}
16+
17+
variable "aws_azs" {
18+
type = string
19+
description = "AWS Availability Zones"
20+
default = "eu-west-2a"
21+
}
22+
23+
variable "enable_dns_hostnames" {
24+
type = bool
25+
description = "Enable DNS hostnames in VPC"
26+
default = true
27+
}
28+
29+
variable "vpc_cidr_block" {
30+
type = string
31+
description = "Base CIDR Block for VPC"
32+
default = "10.0.0.0/16"
33+
}
34+
35+
variable "vpc_public_subnets_cidr_block" {
36+
type = string
37+
description = "CIDR Block for Public Subnets in VPC"
38+
default = "10.0.0.0/24"
39+
}
40+
41+
variable "vpc_private_subnets_cidr_block" {
42+
type = string
43+
description = "CIDR Block for Private Subnets in VPC"
44+
default = "10.0.1.0/24"
45+
}
46+
47+
variable "instance_type" {
48+
type = string
49+
description = "Type for EC2 Instance"
50+
default = "t2.micro"
51+
}
52+
53+
variable "use_custom_ami" {
54+
type = bool
55+
description = "Use custom image"
56+
default = false
57+
}

terraform/account-wide-infrastructure/modules/athena/outputs.tf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,11 @@ output "workgroup" {
55
output "bucket" {
66
value = aws_s3_bucket.athena
77
}
8+
9+
output "bucket_arn" {
10+
value = aws_s3_bucket.athena.arn
11+
}
12+
13+
output "kms_key_arn" {
14+
value = aws_kms_key.athena.arn
15+
}

terraform/account-wide-infrastructure/modules/athena/s3.tf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,23 @@ resource "aws_s3_bucket_policy" "athena" {
2626
}
2727
}
2828
},
29+
{
30+
Sid : "AllowAthenaAccess",
31+
Effect : "Allow",
32+
Principal : {
33+
Service : "athena.amazonaws.com"
34+
},
35+
Action : [
36+
"s3:PutObject",
37+
"s3:GetBucketLocation",
38+
"s3:GetObject",
39+
"s3:ListBucket"
40+
],
41+
Resource : [
42+
aws_s3_bucket.athena.arn,
43+
"${aws_s3_bucket.athena.arn}/*",
44+
]
45+
},
2946
]
3047
})
3148
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
data "aws_ami" "windows-2019" {
2+
most_recent = true
3+
owners = ["amazon"]
4+
filter {
5+
name = "name"
6+
values = ["Windows_Server-2019-English-Full-Base*"]
7+
}
8+
}
9+
10+
data "aws_ami" "PowerBI_Gateway" {
11+
most_recent = true
12+
owners = ["self"]
13+
filter {
14+
name = "name"
15+
values = ["PowerBI_GW"]
16+
}
17+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
resource "aws_instance" "web" {
2+
associate_public_ip_address = false
3+
iam_instance_profile = aws_iam_instance_profile.powerbi_profile.name
4+
ami = local.selected_ami_id
5+
instance_type = var.instance_type
6+
key_name = aws_key_pair.ec2_key_pair.key_name
7+
subnet_id = var.subnet_id
8+
security_groups = var.security_groups
9+
10+
user_data = file("${path.module}/scripts/user_data.tpl")
11+
12+
tags = {
13+
Name = "${var.name_prefix}-ec2"
14+
}
15+
16+
}
17+
18+
resource "tls_private_key" "instance_key_pair" {
19+
algorithm = "RSA"
20+
}
21+
22+
resource "aws_key_pair" "ec2_key_pair" {
23+
key_name = "${var.name_prefix}_PowerBI-GateWay-Key"
24+
public_key = tls_private_key.instance_key_pair.public_key_openssh
25+
}
26+
27+
resource "local_file" "ssh_key_priv" {
28+
filename = "${path.module}/keys/${aws_key_pair.ec2_key_pair.key_name}.pem"
29+
content = tls_private_key.instance_key_pair.private_key_pem
30+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
resource "aws_iam_role" "ec2_service_role" {
2+
name = "${var.name_prefix}-ec2_service_role"
3+
4+
assume_role_policy = jsonencode({
5+
"Version" : "2012-10-17",
6+
"Statement" : [
7+
{
8+
"Effect" : "Allow",
9+
"Principal" : {
10+
"Service" : "ec2.amazonaws.com"
11+
},
12+
"Action" : "sts:AssumeRole"
13+
}
14+
]
15+
})
16+
}
17+
18+
data "aws_iam_policy_document" "ec2_service" {
19+
statement {
20+
actions = [
21+
"s3:GetBucketLocation",
22+
"s3:GetObject",
23+
"s3:ListBucket",
24+
"s3:ListBucketMultipartUploads",
25+
"s3:ListMultipartUploadParts",
26+
"s3:AbortMultipartUpload",
27+
"s3:CreateBucket",
28+
"s3:PutObject",
29+
"s3:PutBucketPublicAccessBlock"
30+
]
31+
32+
resources = compact([
33+
var.target_bucket_arn,
34+
"${var.target_bucket_arn}/*",
35+
var.athena_bucket_arn,
36+
"${var.athena_bucket_arn}/*",
37+
])
38+
effect = "Allow"
39+
}
40+
41+
statement {
42+
actions = [
43+
"s3:ListBucket",
44+
"s3:GetBucketLocation",
45+
"s3:ListAllMyBuckets"
46+
]
47+
48+
resources = compact([
49+
"*"
50+
])
51+
effect = "Allow"
52+
}
53+
54+
statement {
55+
actions = [
56+
"kms:DescribeKey",
57+
"kms:GenerateDataKey*",
58+
"kms:Encrypt",
59+
"kms:ReEncrypt*",
60+
"kms:Decrypt",
61+
]
62+
63+
resources = [
64+
var.glue_kms_key_arn,
65+
var.athena_kms_key_arn,
66+
]
67+
68+
effect = "Allow"
69+
}
70+
71+
statement {
72+
actions = [
73+
"athena:*",
74+
]
75+
effect = "Allow"
76+
resources = [
77+
"*"
78+
]
79+
}
80+
81+
statement {
82+
actions = [
83+
"glue:*",
84+
]
85+
effect = "Allow"
86+
resources = [
87+
"*"
88+
]
89+
}
90+
}
91+
92+
resource "aws_iam_policy" "ec2_service" {
93+
name = "${var.name_prefix}-ec2"
94+
policy = data.aws_iam_policy_document.ec2_service.json
95+
}
96+
97+
resource "aws_iam_role_policy_attachment" "ec2_role_policy" {
98+
role = aws_iam_role.ec2_service_role.name
99+
policy_arn = aws_iam_policy.ec2_service.arn
100+
}
101+
102+
resource "aws_iam_role_policy_attachment" "ec2_role_policy_ssm" {
103+
role = aws_iam_role.ec2_service_role.name
104+
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
105+
}
106+
107+
resource "aws_iam_instance_profile" "powerbi_profile" {
108+
name = "${var.name_prefix}-powerbi_instance_profile"
109+
role = aws_iam_role.ec2_service_role.name
110+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
locals {
2+
selected_ami_id = var.use_custom_ami ? data.aws_ami.PowerBI_Gateway.id : data.aws_ami.windows-2019.id
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
output "instance_id" {
2+
value = aws_instance.web.id
3+
}
4+
5+
output "public_ip" {
6+
value = aws_instance.web.public_ip
7+
}

0 commit comments

Comments
 (0)