Post

OpenVPN CloudFormation

CloudFormation template for creating an automated VPN solution for AWS. This template will create an EC2 instance with the bootstrap script for installing OpenVPN, which can be placed in a VPC of your choice to create a secure way of connecting to the infrastructure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
---
AWSTemplateFormatVersion : 2010-09-09
Description : Add OpenVPN EC2 to VPC
# Specifie parameters for the stack.
Parameters:
  ProjectName:
    Description: This will be used for for resource names, keyname and tagging. Resource name can include letters (A-Z and a-z), and dashes (-).
    Type: String
    MinLength: "3"
    Default: vpn
  AdminFullName:
    Description: Enter Administrator first and last name with "-" in the middle, no spaces.
    Type: String
    Default: firstname-lastname
  Email:
    Description: Enter email address for Amazon Simple Email Service
    Type: String
    Default: example@email.com
  Organization:
    Description: Enter Organization unit name
    Type: String
    Default: DevOps-team
  Company:
    Description: Enter Company name
    Type: String
    Default: Valcon
  VpcID:
    Description: Which VPC would you like to use for Ec2 instance?
    Type: AWS::EC2::VPC::Id
    ConstraintDescription : VPC must exist
  PublicSubnet:
    Description: Which Public Subnet would you like to use for the Ec2 instance?
    Type: AWS::EC2::Subnet::Id
    ConstraintDescription : Subnet must exist
  InstanceType:
    Type: String
    AllowedValues:
      - t2.micro
      - t2.small
      - t2.medium
    Default: t2.micro
    Description : Select Instance Type.
  AmiId:
    Description: Region specific AMI from the Parameter Store
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/canonical/ubuntu/server/20.04/stable/current/amd64/hvm/ebs-gp2/ami-id
    ConstraintDescription: Please enter Ubuntu AMI link
  OpenVPNKeyPair:
    Description: Which SSH Key would you like to use for remote access to Ec2 instance?
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription : Key Pair must exist
  SSHSourceCidr:
    Description: Enter IPv4 address allowed to access your OpenVPN Host via SSH?
    Type: String
    Default: 0.0.0.0/0
    AllowedPattern: "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/([0-9]|[1-2][0-9]|3[0-2]))?$"
    ConstraintDescription: The value must be valid IPv4 CIDR block.
# Provide additional information about the template.
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Connect to AWS resources with OpenVPN"
        Parameters:
          - ProjectName
          - AdminFullName
          - Email
          - Organization
          - Company
          - VpcID
          - PublicSubnet
          - InstanceType
          - AmiId
          - OpenVPNKeyPair
          - SSHSourceCidr
    ParameterLabels:
      ProjectName:
        default: "Resources names"
      AdminFullName:
        default: "Admin name"
      Email:
        default: "Admin email"
      Organization:
        default: "Organization unit name"
      Company:
        default: "Company name"
      VpcID:
        default: "Select VPC"
      PublicSubnet:
        default: "Select Subnet"
      InstanceType:
        default: "Select instance type"
      AmiId:
        default: "Select instance AMI"
      OpenVPNKeyPair:
        default: "Allowed SSH KEY"
      SSHSourceCidr:
        default: "Allowed IP addresses"
# Specify the stack resources and their properties.
Resources:
  # Create ENI
  VPNENI:
      Type: AWS::EC2::NetworkInterface
      Properties:
         Description: OpenVPN ENI for FlowLogs
         SubnetId: !Ref PublicSubnet
         GroupSet:
         - !Ref OpenVPNSecurityGroup
         Tags:
         - Key: Name
           Value: !Sub ${ProjectName}.VPN-ENI
         - Key: Project
           Value: !Sub ${ProjectName}
  # Create EIP for OpenVPN
  ElasticIP:
    Type: AWS::EC2::EIP
    Properties:
      InstanceId: !Ref OpenVPN
      Tags:
        - Key: Name
          Value: !Sub ${ProjectName}.VPN-EIP
        - Key: Project
          Value: !Sub ${ProjectName}
  # S3 bucket for the list of users
  UsersBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${ProjectName}.users-bucket
      LifecycleConfiguration: 
        Rules: 
        - Id: 120 day delete artifacts rule
          Prefix: !Sub '${ProjectName}.users'
          Status: Enabled
          ExpirationInDays: 120
      AccessControl: Private
      VersioningConfiguration: 
        Status: Enabled
      Tags:
        - Key: Project
          Value: !Sub ${ProjectName}
  # UsersBucket bucket policy
  UsersBucketPolicy: 
    Type: AWS::S3::BucketPolicy 
    DependsOn: OpenVPN
    Properties:
      Bucket: !Ref UsersBucket
      PolicyDocument: 
        Version: "2008-10-17"
        Statement:
          -
            Action:
              - s3:ListBucket
              - s3:GetObject
              - s3:PutObject
            Effect: Allow
            Resource:
              - !Sub 'arn:aws:s3:::${UsersBucket}'
              - !Sub 'arn:aws:s3:::${UsersBucket}/*'
            Principal:
              AWS:
                - !Sub 'arn:aws:iam::${AWS::AccountId}:root'
                - !GetAtt OpenVPNRole.Arn
# Create EC2 Instance for the OpenVPN.
  OpenVPN:
    Type: AWS::EC2::Instance
    Properties:
      KeyName: !Ref OpenVPNKeyPair
      BlockDeviceMappings:
      - DeviceName: /dev/sda1
        Ebs:
          VolumeType: gp2
          VolumeSize: 16
      ImageId: !Ref AmiId
      InstanceType: !Ref InstanceType
      InstanceInitiatedShutdownBehavior: stop
      DisableApiTermination: false
      IamInstanceProfile: !Ref OpenVPNIamProfile
      NetworkInterfaces:
      - NetworkInterfaceId: !Ref VPNENI
        DeviceIndex: "0"
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          
          git clone https://<token>@github.com/valconsee//VPN.git /root/OpenVPN
          
          cat <<EOF > /root/start_OpenVPN.sh
          #!/bin/bash -xe

          #VAR
          ADMINUSER="${AdminFullName}"
          EMAIL="${Email}"
          ORG="${Organization}"
          COMPANY="${Company}"
          CITY="${AWS::Region}"
          PROJECT="${ProjectName}"
          EOF

          cat /root/OpenVPN/AWS/bash.sh >> /root/start_OpenVPN.sh
          rm -rf /root/OpenVPN
          chmod -x /root/start_OpenVPN.sh
          bash /root/start_OpenVPN.sh
          cat <<EOF > ~/vpncron
          0 0 * * sat yum -y update --security
          1 0 * * * iptables -t nat -A POSTROUTING -s 10.8.0.0/16 -o "$NETADAPT" -j MASQUERADE
          2 0 * * * iptables -t nat -I POSTROUTING -s 10.8.0.0/16 -d 10.0.0.0/16 -o "$NETADAPT" -j MASQUERADE
          3 0 * * * iptables-save
          EOF
          crontab ~/vpncron
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource myASG --region ${AWS::Region}
      Tags:
        - Key: Name
          Value: !Sub ${ProjectName}.Ec2.${InstanceType}
        - Key: Description
          Value: !Sub OpenVPN EC2 instance for ${ProjectName}
        - Key: Project
          Value: !Sub ${ProjectName}
  # Create Security grope for allowing the ingres on port 1194 and 22.
  OpenVPNSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VpcID
      GroupName: !Sub ${ProjectName}.SG
      GroupDescription: Security group for OpenVPN
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref SSHSourceCidr
      - IpProtocol: udp
        FromPort: 1194
        ToPort: 1194
        CidrIp: !Ref SSHSourceCidr
      Tags:
        - Key: Name
          Value: !Sub ${ProjectName}.VPN-SG
        - Key: Project
          Value: !Sub ${ProjectName}
  # Create IAM profile for OpenVPN instance.
  OpenVPNIamProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles: [!Ref OpenVPNRole]
  # Create Role for OpenVPN instance.
  OpenVPNRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${ProjectName}.AllowDescribeRole
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
  # Create Policy for allowing Describe.
  OpenVPNPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub ${ProjectName}.AllowDescribePolicy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - "ec2:DescribeTags"
              - "ec2:DescribeRegions"
              - "ec2:DescribeInstances"
            Resource: "*"
      Roles:
        - !Ref OpenVPNRole
  VPNssmPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub ${ProjectName}.AllowSSMPolicy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - "ssm:ListDocuments"
              - "ssm:DescribeDocument*"
              - "ssm:GetDocument"
              - "ssm:DescribeInstance*"
            Resource: "*"
      Roles:
        - !Ref OpenVPNRole
  VPNs3Policy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub ${ProjectName}.AllowS3toEc2Policy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - "s3:GetObject"
            Resource:
              - !Sub 'arn:aws:s3:::${UsersBucket}'
              - !Sub 'arn:aws:s3:::${UsersBucket}/*'
      Roles:
        - !Ref OpenVPNRole
  VPNsesPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: !Sub ${ProjectName}.AllowSESPolicy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - "ses:SendEmail"
              - "ses:SendRawEmail"
            Resource: "*"
      Roles:
        - !Ref OpenVPNRole
  # Amazon Simple Email Service
  EmailVerification:
    Type: "AWS::SES::EmailIdentity"
    Properties:
        EmailIdentity: !Ref Email
  SESReceiptRuleSet:
    Type: "AWS::SES::ReceiptRuleSet"
    Properties:
      RuleSetName: "DefaultRuleSet"
  # Log
  LogRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            Service: vpc-flow-logs.amazonaws.com
          Action: sts:AssumeRole
      Policies:
      - PolicyName: flowlogs-policy
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Action:
            - "logs:CreateLogStream"
            - "logs:PutLogEvents"
            - "logs:DescribeLogGroups"
            - "logs:DescribeLogStreams"
            Resource: !GetAtt LogGroup.Arn
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 90
  FlowLog:
    Type: AWS::EC2::FlowLog
    Properties:
      DeliverLogsPermissionArn: !GetAtt LogRole.Arn
      LogGroupName: !Ref LogGroup
      ResourceId: !Ref VPNENI
      ResourceType: NetworkInterface
      TrafficType: ALL
### Parameters
  ProjectParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub '${ProjectName}.project'
      Type: String
      Value: !Ref ProjectName
      Description: SSM Parameter for Project name
  EIPParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub '${ProjectName}.Ec2-Ip'
      Type: String
      Value: !GetAtt OpenVPN.PublicIp
      Description: SSM Parameter for OpenVPN EIP
    DependsOn: OpenVPN
  Ec2IpParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub '${ProjectName}.Ec2-Id'
      Type: String
      Value: !Ref OpenVPN
      Description: SSM Parameter for OpenVPN ec2 ID
    DependsOn: OpenVPN
  S3IdParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub '${ProjectName}.S3-Id'
      Type: String
      Value: !Ref UsersBucket
      Description: SSM Parameter for Users S3 bucket name
    DependsOn: UsersBucket
  EmailParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub '${ProjectName}.ses-email'
      Type: String
      Value: !Ref Email
      Description: SSM Parameter for SES email sending
    DependsOn: UsersBucket
#Names and values for the resources.
Outputs:
  OpenVPNIP:
    Description: OpenVPN Public IP
    Value: !GetAtt OpenVPN.PublicIp
  OpenVPNUser:
    Description: Connect to the instance and run as sudo user in the root directory to create user.
    Value: ./create_vpn_user <firstname-lastname>
This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.