Expose - Expose a web service on localhost to public internet using AWS EC2¶
Expose - Main Module¶
- class expose.main.Tunnel(logger: Optional[Logger] = None)¶
Initiates
Tunnel
object to spin up an EC2 instance with a pre-configured AMI which acts as a tunnel.>>> Tunnel
Instantiates all required AWS resources.
- Parameters:
logger – Bring your own logger.
- init(start: bool) None ¶
Initializer function.
- Parameters:
start – Boolean flag to indicate if its startup or shutdown.
- create_key_pair() bool ¶
Creates a
KeyPair
of typeRSA
stored as aPEM
file to use withOpenSSH
.- Returns:
Boolean flag to indicate the calling function if a
KeyPair
was created.- Return type:
bool
- get_vpc_id() Optional[str] ¶
Fetches the default VPC id.
- Returns:
Default VPC id.
- Return type:
Union[str, None]
- authorize_security_group(security_group_id: str, public_ip: str) bool ¶
Authorizes the security group, to allow ingress and egress traffic via VPC on certain ports.
- Parameters:
security_group_id – Takes the SecurityGroup ID as an argument.
public_ip – Public IP address of the ec2 instance.
See also
- Ports allowed:
22: Only for ec2 and host machine’s public IP with CIDR notation 32.
80: HTTP port for self.
443: HTTPS port for self.
Apart from the above, the SG is authorized for the port number requested to forward.
- Returns:
Boolean flag to indicate the calling function whether the security group was authorized successfully.
- Return type:
bool
- create_security_group() Optional[str] ¶
Gets VPC id and creates a security group for the ec2 instance.
Warning
Deletes and re-creates the SG, in case an SG exists with the same name already.
- Returns:
SecurityGroup ID
- Return type:
Union[str, None]
- create_ec2_instance() Optional[Tuple[str, str]] ¶
Creates an EC2 instance with a pre-configured AMI id.
- Returns:
Instance ID, SecurityGroup ID if successful.
- Return type:
Union[Tuple[str, str], None]
- delete_key_pair() bool ¶
Deletes the
KeyPair
created to access the ec2 instance.- Returns:
Boolean flag to indicate the calling function if the KeyPair was deleted successfully.
- Return type:
bool
- disassociate_security_group(security_group_id: str, instance: Optional[object] = None, instance_id: Optional[str] = None) bool ¶
Disassociates an SG from the ec2 instance by assigning it to the default security group.
- Parameters:
security_group_id – Security group ID
instance – Instance object.
instance_id – Instance ID if object is unavailable.
- Returns:
Boolean flag to indicate the calling function whether the disassociation was successful.
- Return type:
bool
- delete_security_group(security_group_id: str) bool ¶
Deletes the security group.
- Parameters:
security_group_id – Takes the SecurityGroup ID as an argument.
- Returns:
Boolean flag to indicate the calling function whether the SecurityGroup was deleted.
- Return type:
bool
- terminate_ec2_instance(instance_id: Optional[str] = None, instance: Optional[object] = None) ServiceResource ¶
Terminates the requested instance.
- Parameters:
instance_id – Takes instance ID as an argument.
instance – Takes the instance object as an optional argument.
- Returns:
Boolean flag to indicate the calling function whether the instance was terminated.
- Return type:
bool
- start(purge: bool = False) None ¶
Starts the reverse proxy server using nginx to initiate port forwarding.
- Parameters:
purge – Boolean flag to delete all AWS resource if initial configuration fails.
See also
Automatic purge works only during initial setup, and not during re-configuration.
References
https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instance-status.html#options
- wait_until_terminated.html
- server_copy(source: str, destination: str) None ¶
Reads a file in localhost and writes it within the ec2 instance using SSH connection.
- Parameters:
source – Name of the source file in localhost.
destination – Name of the destination file in the server.
- get_config(filename: str, server: str) str ¶
Loads the configuration file and returns the data.
- Parameters:
filename – Name of the file that has to be downloaded.
server – Custom server names to be added in configuration files.
- Returns:
Returns the data of the file as a string.
- Return type:
str
- config_requirements(common_name: str, custom_servers: str, san_list: List[str]) Dict[str, str] ¶
Tries to create a self-signed SSL certificate and loads all the required configuration into a dictionary.
- Parameters:
common_name – DNS entry for SSL creation.
custom_servers – Server names to be loaded in the nginx config files.
san_list – Subject Alternative Names to validate the certificate for.
- Returns:
Dictionary of config file name and the configuration data.
- Return type:
Dict[str, str]
- configure_vm(public_dns: str, public_ip: str, disposal: bool = False) None ¶
Configures the ec2 instance to take traffic from localhost and initiates tunneling.
- Parameters:
public_dns – Public DNS name of the EC2 that was created.
public_ip – Public IP of the EC2 that was created.
disposal – Boolean flag to delete all AWS resources on failed configuration.
- stop(instance_id: Optional[str] = None, security_group_id: Optional[str] = None, public_ip: Optional[str] = None) None ¶
Disables tunnelling by removing all AWS resources acquired.
- Parameters:
instance_id – Instance that has to be terminated.
security_group_id – Security group that has to be removed.
public_ip – Public IP address to delete the A record from route53.
See also
Doesn’t require any argument, as long as the JSON dump is neither removed nor modified by hand.
References
- wait_until_terminated.html
Expose - Auxiliary¶
- expose.models.auxiliary.write_screen(text: Any) None ¶
Write text on screen that can be cleared later.
- Parameters:
text – Text to be written.
- expose.models.auxiliary.flush_screen() None ¶
Flushes the screen output.
See also
Writes new set of empty strings for the size of the terminal if ran using one.
Expose - Certificates¶
- expose.models.cert._get_serial() bytes ¶
Generates a serial number for the self-signed SSL.
See also
This function is not called, but it is here only as a just in case measure to insert serial number manually.
Serial Number is a unique identifier assigned by the CA which issued the certificate.
- Returns:
Encoded serial number for the certificate.
- Return type:
bytes
- expose.models.cert._generate_serial_hash(byte_size: int = 18, int_size: int = 36) int ¶
Generates a hashed serial number.
- Parameters:
byte_size – Size of the bytes object containing random bytes.
int_size – Size of the base int.
- Returns:
Returns the hashed serial.
- Return type:
int
- expose.models.cert.generate_cert(common_name: str, san_list: List[str], country_name: str = 'US', locality_name: str = 'Springfield', state_or_province_name: str = 'Missouri', organization_unit_name: str = 'Information Technology', key_file: str = 'private.pem', cert_file: str = 'public.pem', key_size: int = 2048) None ¶
Creates a self-signed certificate.
- Parameters:
common_name – DNS name of the origin.
country_name – Name of the country. Defaults to
US
locality_name – Name of the city. Defaults to
New York
state_or_province_name – Name of the state/province. Defaults to
New York
organization_unit_name – Name of the organization unit. Defaults to
Information Technology
key_file – Name of the key file.
cert_file – Name of the certificate.
key_size – Size of the public key. Defaults to 2048.
san_list – List of Subject Alternative Names (SANs). Defaults to None.
See also
Use
openssl x509 -inform pem -in public.pem -noout -text
to look at the generated cert using openssl.
Expose - Configuration¶
- class expose.models.config.AMIBase(pydantic.BaseModel)¶
Default values to fetch AMI image ID.
>>> AMIBase
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
__init__ uses __pydantic_self__ instead of the more common self for the first arg to allow self as a field name.
- _BASE_URL: str = ModelPrivateAttr(default='https://aws.amazon.com/marketplace/server/configuration?productId={productId}')¶
- _BASE_SSM: str = ModelPrivateAttr(default='/aws/service/marketplace/prod-{path}')¶
- PRODUCT_PAGE: Url¶
- NAME: str¶
- ALIAS: str¶
- PRODUCT_CODE: str¶
- S_PRODUCT_PAGE: Url¶
- S_NAME: str¶
- S_ALIAS: str¶
- S_PRODUCT_CODE: str¶
- model_post_init(__context: Any) None ¶
This function is meant to behave like a BaseModel method to initialise private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- Parameters:
self – The BaseModel instance.
__context – The context.
- class expose.models.config.EnvConfig(pydantic_settings.BaseSettings)¶
Env configuration.
>>> EnvConfig
References
https://docs.pydantic.dev/2.3/migration/#required-optional-and-nullable-fields
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
__init__ uses __pydantic_self__ instead of the more common self for the first arg to allow self as a field name.
- port: int¶
- open_port: bool¶
- channel_timeout: int¶
- image_id: Optional[str]¶
- instance_type: str¶
- aws_region_name: str¶
- key_pair: str¶
- security_group: str¶
- key_file: str¶
- cert_file: str¶
- server_info: str¶
- hosted_zone: Optional[str]¶
- subdomain: Optional[str]¶
- aws_access_key: Optional[str]¶
- aws_secret_key: Optional[str]¶
- email_address: EmailStr¶
- organization: Optional[str]¶
- class expose.models.config.Settings(pydantic.BaseModel)¶
Wrapper for AWS settings.
>>> Settings
Create a new model by parsing and validating input data from keyword arguments.
Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.
__init__ uses __pydantic_self__ instead of the more common self for the first arg to allow self as a field name.
- interactive: bool¶
- current_dir: Path¶
- ssh_home: str¶
- key_pair_file: Path¶
- configuration: Path¶
- ami_deprecation: int¶
- entrypoint: str¶
- nginx_config_commands: Dict[str, bool]¶
Expose - Exceptions¶
- exception expose.models.exceptions.NotImplementedWarning¶
Custom implementation warning.
- exception expose.models.exceptions.DuplicateResource¶
Custom validation error for duplicate AWS resources.
- exception expose.models.exceptions.AWSResourceError(status_code: int, error_msg: str)¶
Custom resource error for AWS resources.
Expose - ImageFactory¶
- expose.models.image_factory.deprecation_warning(image_id: str, deprecation_time: str) None ¶
Raises a deprecation warning if the chosen AMI is nearing (value is set in config) its DeprecationTime.
- class expose.models.image_factory.ImageFactory(session: Session, logger: Logger)¶
Handles retrieving AMI ID from multiple sources.
>>> ImageFactory
Instantiates the
ImageFactory
object.- Parameters:
session – boto3 session instantiated in the origin class.
logger – Custom logger.
- get_ami_id_ssm() str ¶
Retrieve AMI ID using Ami Alias.
- get_ami_id_product_code() str ¶
Retrieve AMI ID using Product Code.
- get_ami_id_name() str ¶
Retrieve AMI ID using Ami Name.
- get_image_id() str ¶
Tries to get image id from multiple sources, sequentially.
See also
Executes in sequence as fastest first. - Alias on SSM points to a single parameter that possibly contains a single AMI ID as its value. - Lookup AMI with image name is specific and possibly points to a single AMI ID. - Lookup AMI with product code will possibly return many images, so grabs the most recently created one.
- Returns:
AMI image ID.
- Return type:
str
- Raises:
If unable to fetch AMI ID from any source. –
Expose - LOGGER¶
Custom logging setup shared across modules.
Expose - Route53¶
- expose.models.route_53.get_zone_id(client: client, logger: Logger, dns: str, init: bool = False) str ¶
Gets the zone ID of a DNS name registered in route53.
- Parameters:
client – Pre-instantiated boto3 client.
logger – Custom logger.
dns – Hosted zone name.
init – Boolean flag to raise an error in case of missing zone ID.
- Returns:
Returns the zone ID.
- Return type:
str or None
- expose.models.route_53.change_record_set(client: client, source: str, destination: str, logger: Logger, zone_id: str, action: str) Optional[Dict] ¶
Changes a record set within an existing hosted zone.
- Parameters:
client – Pre-instantiated boto3 client.
source – Source DNS name.
destination – Destination hostname or IP address.
logger – Custom logger.
zone_id – Hosted zone ID.
action – Action to perform. Example: UPSERT or DELETE
- Returns:
ChangeSet response from AWS.
- Return type:
dict or None
Expose - Server Configuration¶
- expose.models.server.join(value: Union[tuple, list, str], separator: str = ':') str ¶
Uses
.join
to squash a list or tuple using a separator.- Parameters:
value – Value to be squashed.
separator – Separator to be used to squash.
- Returns:
A squashed string.
- Return type:
str
- expose.models.server.print_warning() None ¶
Prints a message on screen to run an app or api on the specific port.
See also
This is a safety net to improve latency.
This function will block instantiating channel transport until the port is locked for tunneling.
- class expose.models.server.Server(hostname: str, logger: Logger, username: str = 'ubuntu', timeout: int = 30)¶
Initiates
Server
object to create an SSH session to configure the server and intiate the tunneling.>>> Server
Reverse SSH Port Forwarding
Specifies that the given port on the remote server host is to be forwarded to the given host and port on the local side. So, instead of your machine doing a simple SSH, the server does an SSH and through the port forwarding makes sure that you can SSH back to the server machine.
Instantiates the session using RSAKey generated from the ec2’s keypair
PEM
file.- Parameters:
hostname – Hostname of the server to connect to.
username – Takes the username of the server to authenticate.
timeout – Connection timeout for SSH server.
- run_ondemand_ssh(ondemand: str, command: str) bool ¶
Runs on demand SSH commands in case of recoverable errors.
- Parameters:
ondemand – Recovery command that needs to run.
command – Original command that failed.
- Returns:
To indicate if recovery failed.
- Return type:
bool
- run_interactive_ssh() bool ¶
Authenticates remote server using a
PEM
file and runs interactive ssh commands.- Returns:
Boolean flag to indicate the calling function if all the commands were executed successfully.
- Return type:
bool
- server_write(data: dict) None ¶
Writes configuration data into dedicated files using FTP.
- Parameters:
data – Takes a dictionary of filename and content as key-value pairs.
- _handler(channel: Channel, port: int) None ¶
Creates a socket and handles TCP IO on the channel created.
- Parameters:
channel – Channel for Transport.
port – Port number on which the socket should connect.
- stop_tunnel(transport: Transport, threads: List[Thread]) None ¶
Stops port forwarding.
- Parameters:
transport – Transport object that creates the channel
threads – Daemon threads handling connections.
- initiate_tunnel() None ¶
Initiates port forwarding using
Transport
which creates a channel.