Skip to content

Instantly share code, notes, and snippets.

@jarjuk
Last active September 24, 2015 15:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jarjuk/7d7789cd0c18d5e51c99 to your computer and use it in GitHub Desktop.
Save jarjuk/7d7789cd0c18d5e51c99 to your computer and use it in GitHub Desktop.
  This gist contains code for blog post [A Nat Instance on AWS](https://jarjuk.wordpress.com/2015/09/21/nat-instance-on-aws)

  * Gemfile : install aws-must-templates Gem being 
  * Rakefile: loading test runner from aws-must-templates
  * suite2.yaml : YAML configuration for CloudFormation stack
  * suite2.json : CloudFormation template generated from suite2.yaml
  * test-suites.yaml: configuration for test runner configuration in YAML
source 'https://rubygems.org'
gem 'aws-must-templates', '=0.2.4'
require 'yaml'
# name of a configuration file
suite_runner_configs= "suite-runner-configs.yaml"
# Override configuration in 'suite.rake'
$suite_runner_configs = File.exist?(suite_runner_configs) ? YAML.load_file( suite_runner_configs ) : {}
# load `suite` namespace
spec = Gem::Specification.find_by_name 'aws-must-templates'
load "#{spec.gem_dir}/lib/tasks/suite.rake"
# http://docs.aws.amazon.com/sdkforruby/api/index.html#Configuration
# "The SDK searches the following locations for a region: ENV['AWS_REGION']"
#
# Test runner sets ENV['AWS_REGION'] if following property is set
aws_region: eu-west-1
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Example configuration for VPC",
"Parameters": {
"InstanceType": {
"Description": "EC2 reousrce instance type",
"Type": "String",
"Default": "t2.micro"
},
"KeyName": {
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the instance",
"Type": "AWS::EC2::KeyPair::KeyName",
"Default": "demo-key"
},
"SSHLocation": {
"Description": "The IP address range that can be used to SSH to the EC2 instances",
"Type": "String",
"Default": "0.0.0.0/0"
}
},
"Mappings": {
"AWSInstanceType2Arch": {
"t2.micro": {
"Arch": "64"
}
},
"AWSRegionArch2AMI": {
"ap-northeast-1": {
"64": "ami-90815290"
},
"ap-southeast-1": {
"64": "ami-0accf458"
},
"ap-southeast-2": {
"64": "ami-1dc8b127"
},
"cn-north-1": {
"64": "ami-eae27fd3"
},
"eu-central-1": {
"64": "ami-3248712f"
},
"eu-west-1": {
"64": "ami-d74437a0"
},
"sa-east-1": {
"64": "ami-0f6ced12"
},
"us-east-1": {
"64": "ami-83c525e8"
},
"us-west-1": {
"64": "ami-61b25925"
},
"us-gov-west-1": {
"64": "ami-51513172"
},
"us-west-2": {
"64": "ami-57e8d767"
}
},
"MappingNatAim": {
"us-east-1": {
"AMI": "ami-184dc970"
},
"us-west-1": {
"AMI": "ami-a98396ec"
},
"us-west-2": {
"AMI": "ami-290f4119"
},
"eu-west-1": {
"AMI": "ami-14913f63"
},
"eu-central-1": {
"AMI": "ami-ae380eb3"
},
"sa-east-1": {
"AMI": "ami-8122969c"
},
"ap-southeast-1": {
"AMI": "ami-6aa38238"
},
"ap-southeast-2": {
"AMI": "ami-893f53b3"
},
"ap-northeast-1": {
"AMI": "ami-27d6e626"
}
}
},
"Resources": {
"MyVPC": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.0.0.0/16",
"EnableDnsSupport": true,
"EnableDnsHostnames": true,
"Tags": [
{
"Key": "Name",
"Value": "MyVPC"
}
]
}
},
"RouteTableNat": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "MyVPC"
},
"Tags": [
{
"Key": "Name",
"Value": "RouteTableNat"
}
]
}
},
"PublicSubnet": {
"Type": "AWS::EC2::Subnet",
"DependsOn": "MyVPC",
"Properties": {
"CidrBlock": "10.0.0.0/24",
"Tags": [
{
"Key": "Name",
"Value": "PublicSubnet"
}
],
"MapPublicIpOnLaunch": true,
"VpcId": {
"Ref": "MyVPC"
}
}
},
"PrivateSubnet": {
"Type": "AWS::EC2::Subnet",
"DependsOn": "MyVPC",
"Properties": {
"CidrBlock": "10.0.1.0/24",
"Tags": [
{
"Key": "Name",
"Value": "PrivateSubnet"
}
],
"MapPublicIpOnLaunch": false,
"VpcId": {
"Ref": "MyVPC"
}
}
},
"PrivateSubnetRouteTableAssociation": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RouteTableNat"
},
"SubnetId": {
"Ref": "PrivateSubnet"
}
}
},
"MyInternetGw": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": "MyInternetGw"
}
]
}
},
"MyInternetGwAttachment": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "MyVPC"
},
"InternetGatewayId": {
"Ref": "MyInternetGw"
}
}
},
"RouteTableMyInternetGw": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "MyVPC"
},
"Tags": [
{
"Key": "Name",
"Value": "RouteTableMyInternetGw"
},
{
"Key": "Application",
"Value": {
"Ref": "AWS::StackId"
}
}
]
}
},
"Route": {
"Type": "AWS::EC2::Route",
"DependsOn": "MyInternetGwAttachment",
"Properties": {
"RouteTableId": {
"Ref": "RouteTableMyInternetGw"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "MyInternetGw"
}
}
},
"RouteTableAssociationPublicSubnet": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "PublicSubnet"
},
"RouteTableId": {
"Ref": "RouteTableMyInternetGw"
}
}
},
"BackendSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Enable SSH access via port 22",
"VpcId": {
"Ref": "MyVPC"
},
"Tags": [
{
"Key": "Name",
"Value": "BackendSecurityGroup"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "icmp",
"FromPort": "-1",
"ToPort": "-1",
"CidrIp": "0.0.0.0/0"
}
],
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": "10.0.0.0/24"
},
{
"IpProtocol": "icmp",
"FromPort": "-1",
"ToPort": "-1",
"CidrIp": "10.0.0.0/16"
}
]
}
},
"FrontEndSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Enable SSH access via port 22",
"VpcId": {
"Ref": "MyVPC"
},
"Tags": [
{
"Key": "Name",
"Value": "FrontEndSecurityGroup"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": "10.0.1.0/24"
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "443",
"ToPort": "443",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "icmp",
"FromPort": "-1",
"ToPort": "-1",
"CidrIp": "0.0.0.0/0"
}
],
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {
"Ref": "SSHLocation"
}
},
{
"IpProtocol": "icmp",
"FromPort": "-1",
"ToPort": "-1",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"NatSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Enable SSH access via port 22",
"VpcId": {
"Ref": "MyVPC"
},
"Tags": [
{
"Key": "Name",
"Value": "NatSecurityGroup"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": "10.0.1.0/24"
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "icmp",
"FromPort": "-1",
"ToPort": "-1",
"CidrIp": "0.0.0.0/0"
}
],
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {
"Ref": "SSHLocation"
}
},
{
"IpProtocol": "icmp",
"FromPort": "-1",
"ToPort": "-1",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "10.0.1.0/24"
}
]
}
},
"myNat": {
"Type": "AWS::EC2::Instance",
"Metadata": {},
"Properties": {
"ImageId": {
"Fn::FindInMap": [
"MappingNatAim",
{
"Ref": "AWS::Region"
},
"AMI"
]
},
"InstanceType": {
"Ref": "InstanceType"
},
"Tags": [
{
"Key": "Name",
"Value": "myNat"
}
],
"SourceDestCheck": false,
"SecurityGroupIds": [
{
"Ref": "NatSecurityGroup"
}
],
"SubnetId": {
"Ref": "PublicSubnet"
},
"KeyName": {
"Ref": "KeyName"
},
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"\n",
[
"#!/bin/bash\n",
"set -x\n",
"set -e\n",
"set -o pipefail\n",
"LOG=/tmp/install.log\n",
"echo $(date): User data script started > $LOG\n",
"echo $(date): User data script started\n",
"function finish() {\n",
" echo \"$(date): installation finished\" \n",
" echo \"$(date): installation finished\" >> $LOG \n",
"}\n",
"function error() {\n",
" local lineno=$1\n",
" local error=1\n",
" echo \"$(date): installation finished in ERROR $error on line $lineno\" \n",
" echo \"$(date): installation finished in ERROR $error on line $lineno\" >> $LOG \n",
" exit 1\n",
"}\n",
"trap finish EXIT\n",
"trap 'error ${LINENO}' ERR\n"
]
]
}
}
}
},
"myBack1": {
"Type": "AWS::EC2::Instance",
"Metadata": {},
"Properties": {
"ImageId": {
"Fn::FindInMap": [
"AWSRegionArch2AMI",
{
"Ref": "AWS::Region"
},
{
"Fn::FindInMap": [
"AWSInstanceType2Arch",
{
"Ref": "InstanceType"
},
"Arch"
]
}
]
},
"InstanceType": {
"Ref": "InstanceType"
},
"Tags": [
{
"Key": "Name",
"Value": "myBack1"
}
],
"SourceDestCheck": true,
"SecurityGroupIds": [
{
"Ref": "BackendSecurityGroup"
}
],
"SubnetId": {
"Ref": "PrivateSubnet"
},
"KeyName": {
"Ref": "KeyName"
},
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"\n",
[
"#!/bin/bash\n",
"set -x\n",
"set -e\n",
"set -o pipefail\n",
"LOG=/tmp/install.log\n",
"echo $(date): User data script started > $LOG\n",
"echo $(date): User data script started\n",
"function finish() {\n",
" echo \"$(date): installation finished\" \n",
" echo \"$(date): installation finished\" >> $LOG \n",
"}\n",
"function error() {\n",
" local lineno=$1\n",
" local error=1\n",
" echo \"$(date): installation finished in ERROR $error on line $lineno\" \n",
" echo \"$(date): installation finished in ERROR $error on line $lineno\" >> $LOG \n",
" exit 1\n",
"}\n",
"trap finish EXIT\n",
"trap 'error ${LINENO}' ERR\n"
]
]
}
}
}
},
"myFront1": {
"Type": "AWS::EC2::Instance",
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT8M"
}
},
"DependsOn": [
"myBack1",
"myNat"
],
"Metadata": {
"AWS::CloudFormation::Init": {
"config": {
"packages": {},
"groups": {},
"users": {},
"sources": {},
"files": {
"/tmp/cfn-init.txt": {
"content": {
"Fn::Join": [
"",
[
"Installed in cfn-init",
"\n"
]
]
},
"mode": "000444",
"owner": "root",
"group": "root"
}
},
"commands": {},
"services": {}
}
}
},
"Properties": {
"ImageId": {
"Fn::FindInMap": [
"AWSRegionArch2AMI",
{
"Ref": "AWS::Region"
},
{
"Fn::FindInMap": [
"AWSInstanceType2Arch",
{
"Ref": "InstanceType"
},
"Arch"
]
}
]
},
"InstanceType": {
"Ref": "InstanceType"
},
"Tags": [
{
"Key": "Name",
"Value": "myFront1"
}
],
"SourceDestCheck": true,
"SecurityGroupIds": [
{
"Ref": "FrontEndSecurityGroup"
}
],
"SubnetId": {
"Ref": "PublicSubnet"
},
"KeyName": {
"Ref": "KeyName"
},
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"\n",
[
"#!/bin/bash\n",
"set -x\n",
"set -e\n",
"set -o pipefail\n",
"LOG=/tmp/install.log\n",
"echo $(date): User data script started > $LOG\n",
"echo $(date): User data script started\n",
"function finish() {\n",
" echo \"$(date): installation finished\" \n",
" echo \"$(date): installation finished\" >> $LOG \n",
" STACK='",
{
"Ref": "AWS::StackName"
},
"'\n",
" REGION='",
{
"Ref": "AWS::Region"
},
"'\n",
" RESOURCE='myFront1'\n",
" type cfn-signal && sudo cfn-signal --success true --reason \"UserData script success\" --stack $STACK --resource $RESOURCE --region $REGION \n",
"}\n",
"function error() {\n",
" local lineno=$1\n",
" local error=1\n",
" echo \"$(date): installation finished in ERROR $error on line $lineno\" \n",
" echo \"$(date): installation finished in ERROR $error on line $lineno\" >> $LOG \n",
" STACK='",
{
"Ref": "AWS::StackName"
},
"'\n",
" REGION='",
{
"Ref": "AWS::Region"
},
"'\n",
" RESOURCE='myFront1'\n",
" type cfn-signal && sudo cfn-signal --exit-code $error --reason \"installation finished in ERROR on line $lineno\" --stack $STACK --resource $RESOURCE --region $REGION \n",
" exit 1\n",
"}\n",
"trap finish EXIT\n",
"trap 'error ${LINENO}' ERR\n",
"echo \"$(date): ------------------------------------------------------------------\" \n",
"echo Install Cloudformation tools \n",
"sudo apt-get -y install python-setuptools \n",
"[ -d aws-cfn-bootstrap-latest ] || mkdir aws-cfn-bootstrap-latest \n",
"curl https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz | tar xz -C aws-cfn-bootstrap-latest --strip-components 1 \n",
"sudo easy_install aws-cfn-bootstrap-latest \n"
]
]
}
}
}
},
"RouteToNat": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "RouteTableNat"
},
"DestinationCidrBlock": "0.0.0.0/0",
"InstanceId": {
"Ref": "myNat"
}
}
}
},
"Outputs": {
"myFront1": {
"Description": "Ip of the newly created EC2 instance",
"Value": {
"Fn::GetAtt": [
"myFront1",
"PublicIp"
]
}
},
"myNat": {
"Description": "Ip of the newly created EC2 instance",
"Value": {
"Fn::GetAtt": [
"myNat",
"PublicIp"
]
}
},
"InstanceId1": {
"Description": "Id of the newly created EC2 instance",
"Value": {
"Ref": "myFront1"
}
},
"InstanceId2": {
"Description": "Id of the newly created EC2 instance",
"Value": {
"Ref": "myBack1"
}
},
"MyInternetGw": {
"Description": "Id of InternetGateway",
"Value": {
"Ref": "MyInternetGw"
}
}
}
}
description: Example configuration for VPC
parameters:
- Name: &Param_InstanceTypeName InstanceType
Type: String
Description: EC2 reousrce instance type
Value: t2.micro
- Name: &Param_KeyName KeyName
Type: "AWS::EC2::KeyPair::KeyName"
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
Value: demo-key
- Name: &Param_SSHLocation SSHLocation
Type: String
Description: The IP address range that can be used to SSH to the EC2 instances
Value: "0.0.0.0/0"
# Define anchors for data value
# Does not generate anything.
#
data:
- SubNets:
- VPC: &SubNetVPC 10.0.0.0/16
- Public: &SubNetPublic 10.0.0.0/24
- Private: &SubNetPrivate 10.0.1.0/24
mappings:
- AmazonVpcNat:
Name: &MappingNatAim MappingNatAim
resources:
- VPC:
Name: &MyVPC MyVPC
CidrBlock: *SubNetVPC
Tags:
- Key: Name
Value: "MyVPC"
- RouteTable:
Name: &RouteTableNat RouteTableNat
Vpc: *MyVPC
# - RouteTable:
# Name: &RouteTableMain RouteTableMain
# Vpc: *MyVPC
- Subnet:
Name: &PublicSubnet PublicSubnet
DependsOn: *MyVPC
MapPublicIpOnLaunch: true
CidrBlock: *SubNetPublic
VpcId: *MyVPC
Tags:
- Key: Name
Value: *PublicSubnet
- Subnet:
Name: &PrivateSubnet PrivateSubnet
DependsOn: *MyVPC
MapPublicIpOnLaunch: false
CidrBlock: *SubNetPrivate
VpcId: *MyVPC
Tags:
- Key: Name
Value: *PrivateSubnet
RoutetableAssociation: *RouteTableNat
- InternetGateway:
Name: &MyInternetGw MyInternetGw
Subnet: *PublicSubnet
Attachment:
AttachmentName: &AttachIgw MyInternetGwAttachment
Vpc: *MyVPC
- SecurityGroup:
Name: &BackendSG BackendSecurityGroup
VpcId:
Ref: *MyVPC
SecurityGroupIngress:
# ssh
- Value: *SubNetPublic
Port: 22
# ping
- Value: *SubNetVPC
FromPort: -1
ToPort: -1
IpProtocol: icmp
SecurityGroupEgress:
- Value: 0.0.0.0/0
Port: 80
- Value: 0.0.0.0/0
FromPort: -1
ToPort: -1
IpProtocol: icmp
- SecurityGroup:
Name: &FrontSG FrontEndSecurityGroup
VpcId:
Ref: *MyVPC
SecurityGroupIngress:
# ssh
- Ref: *Param_SSHLocation
Port: 22
# Ping
- Value: 0.0.0.0/0
FromPort: -1
ToPort: -1
IpProtocol: icmp
# Http from private net
- Value: 0.0.0.0/0
Port: 80
SecurityGroupEgress:
- Value: *SubNetPrivate
Port: 22
- Value: 0.0.0.0/0
Port: 80
- Value: 0.0.0.0/0
Port: 443
- Value: 0.0.0.0/0
FromPort: -1
ToPort: -1
IpProtocol: icmp
- SecurityGroup:
Name: &NatSG NatSecurityGroup
VpcId:
Ref: *MyVPC
SecurityGroupIngress:
# ssh
- Ref: *Param_SSHLocation
Port: 22
# Ping
- Value: 0.0.0.0/0
FromPort: -1
ToPort: -1
IpProtocol: icmp
# Http from private net
- Value: *SubNetPrivate
Port: 80
SecurityGroupEgress:
- Value: *SubNetPrivate
Port: 22
- Value: 0.0.0.0/0
Port: 80
- Value: 0.0.0.0/0
FromPort: -1
ToPort: -1
IpProtocol: icmp
- Instance:
Name: &Instance3 myNat
InstanceTypeRef: *Param_InstanceTypeName
MapRegionToImageId: *MappingNatAim
KeyName: *Param_KeyName
# For the instance to perform NAT, the value must be
# "false". Notice String!!!
SourceDestCheck: "false"
# CreationPolicy:
# Timeout: PT8M
# Initialize:
# - InstallCFtools: true
# DependsOn:
# - *AttachIgw
SubnetId:
- Ref: *PublicSubnet
SecurityGroupIds:
- Ref: *NatSG
- Instance:
Name: &Instance2 myBack1
InstanceTypeRef: *Param_InstanceTypeName
KeyName: *Param_KeyName
# Fails because no internet connection to download
# cfn-tools
# CreationPolicy:
# Timeout: PT8M
# Initialize:
# - InstallCFtools: true
SubnetId:
- Ref: *PrivateSubnet
SecurityGroupIds:
- Ref: *BackendSG
- Instance:
Name: &Instance1 myFront1
InstanceTypeRef: *Param_InstanceTypeName
KeyName: *Param_KeyName
DependsOn:
- *Instance2
- *Instance3
CreationPolicy:
Timeout: PT8M
Initialize:
- InstallCFtools: true
SubnetId:
- Ref: *PublicSubnet
SecurityGroupIds:
- Ref: *FrontSG
- Route:
Name: RouteToNat
Vpc: *MyVPC
# DependsOn:
# - *AttachIgw
RouteTableId: *RouteTableNat
InstanceId: *Instance3
DestinationCidrBlock: "0.0.0.0/0"
# - Route:
# Name: RouteMain
# Vpc: *MyVPC
# RouteTableId: *RouteTableMain
# GatewayId: *MyInternetGw
# DestinationCidrBlock: "0.0.0.0/0"
outputs:
- Name: *Instance1
Description: Ip of the newly created EC2 instance
Attr:
Ref: *Instance1
Name: PublicIp
- Name: *Instance3
Description: Ip of the newly created EC2 instance
Attr:
Ref: *Instance3
Name: PublicIp
# - Name: *Instance2
# Description: Ip of the newly created EC2 instance
# Attr:
# Ref: *Instance2
# Name: PublicIp
- Name: InstanceId1
Description: Id of the newly created EC2 instance
Ref: *Instance1
- Name: InstanceId2
Description: Id of the newly created EC2 instance
Ref: *Instance2
- Name: *MyInternetGw
Description: Id of InternetGateway
Ref: *MyInternetGw
- suite2:
desc: VPC with Public and Private Subnets (NAT)
instances:
- myFront1:
roles:
- RespondsToPing:
- NetworkCanPing:
Destination: www.google.com
- myBack1:
roles:
- NetworkCanPing:
Destination: www.google.com
- Ec2Routes:
Routes:
- :gateway_id: local
:state: active
:destination_cidr_block: "10.0.0.0/16"
- :destination_cidr_block: "0.0.0.0/0"
:state: active
:instance_id: !ruby/regexp '/^i-.*/'
- myNat:
roles:
- RespondsToPing:
- Ec2SecurityGroups:
StrictIngress: false
StrictEgress: false
Ingress:
- :ip_protocol: icmp
:from_port: -1
:to_port: -1
:ip_ranges:
- :cidr_ip: "0.0.0.0/0"
Egress:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment