I was at the AI connect meetup with the title Data Science for Social Good. Came to know how college students and professionals can contribute to the social good. When they shared about the hackathon. Like a kid in a candy store, I was excited to join the hackathon. I had been looking for a way to give back to the community and this was the perfect opportunity.
As soon as I signed up for the hackathon, I started looking for a team from the participant list.
Based on what I understood from the AI connect meetup, I was in the mindset of having a team with necessary skills. I have architectural, DevOps and design thinking skills that can break down the problem into actionable items for each team member. But I don’t want to sign up to be a developer, especially as a front-end developer. So I was looking for
Even though I connected with a few participants, I wasn’t able to form a team but made a few friends who were open to discuss and decide at the Mixer.
After the welcome speech, we started the mixer to find a team. It was recommended to find a team with 4-6 members.
Initially I found a team with smart and young developers. In the middle of forming a team, I went to look for a product owner/scrum master who can identify smaller scope that is achivable and manage coordination when friction occurs. By the time I come around, this team had more members. Everyone loves doers.
I restarted looking for a team where I could be an architect, DevOps engineer, or at worst case, a backend developer. As I approached and introduced myself by telling them who I am and what I can do, they were more than happy to have me as part of the team.
Team formed and my teammates are
- Anthony Chapman: Frontend developer
- Lucas Wyman: CEO type with marketing skills, lots of energy, passion to solve problems, and strong presentation skills
- Matthew Lucas: Backend developer
- Don Huovinen: Product owner type; skilled in low-code/no-code development
- Danny Logsdon: CEO type with expertise in generating backend code using .NET
- and myself (Mahendran Mookkiah): Architect, AWS DevOps
As teams were seated, there were a few members looking for a team. At the stage, they were asked to share their skills and what they could do. As soon as Bill Davis shared that he is a PowerBI expert, Danny raised his hand to welcome Bill to the team. I sensed Danny’s people skills and his supportive, “not leaving anyone behind” mindset.
Excited to see the problem cases.
We had three problem cases to solve. This is not the full case details. The section I understand.
To fill the gap between civic engagement and electoral engagement. Research the given dataset and design a method, tool, or platform to measure non-electoral civic engagement in Duval County. Use creative data sourcing to answer: “In what ways and how many North Floridians are engaging in civic life outside of voting?”
Develop a Self-Sufficiency standard framework that helps gather data that will allow the community to better estimate the true cost of self-sufficiency in Duval County. This helps incoming residents find the region within our county that suits their needs and budget. This also helps local leaders make funding decisions, policy development, and design regional development programs to improve the community.
The goal is to foster collaboration between non-profits, local organizations and volunteers/donations to maximize resource allocation. We need a platform to bring the donating people and organization to list their donations. Reduce the friction in delivering the donations to the people who is looking for it. Increase the transparency of how a donation reaches who and when so that the donors trust the platform and give more.
This is the case we have chosen to implement.
As we started digesting “Community Connections” problem, our team started seeing the complexity and large scope of this project. This includes…
In order to build a working demo in 48 hours, we had to find a smaller and impactful idea. We decided to focus on organizations as customers and bring them a screen to show opportunities to donate. We also wanted to give every one of our team members the opportunity to contribute with their existing skills or something quick to learn. We were able to take on these tasks:
By Saturday evening at 3 PM (~24 hours), we had a clear idea of everyone’s task and were able to dream about putting it all together and presenting.
Thank everyone involved. This is your chance to show appreciation.
We were thrilled to win 2nd place in the hackathon! This recognition validated our team’s hard work and the impact potential of our Community Connections platform.
As a team, we decided to donate a portion of our winnings to Mission House, a local Jacksonville Beach non-profit that empowers and compassionately supports neighbors in need. Their mission of helping people achieve stable, healthy, and self-sufficient lives aligns perfectly with our hackathon’s goal of fostering community connections and resource allocation.
This donation represents our commitment to not just building solutions during the hackathon, but continuing to support the community we’re trying to help.
Hackathons are for quickly prototyping a challenge with technical experts. We were proud to contribute. The success is in capturing the thoughts of every team which tackles this problem case and brainstorming to build a product. We’re happy to hear this project will continue beyond the hackathon to create impact in the community.
]]>AWS provides easy to setup email platform that enables capability to send emails from application. Application developers can create template that managed outside of application code. DevOps can create configuration set to based on use cases that limits, adds secrity and improve reputation.
In this page, we are sharing basics of SES setup and value of properly managing suppression lists and virtual delivery manager.
Identity is about expressing our ownership towards a domain or individual email addresses that we work with. AWS platform allows us to begin work with sandbox environment to begin the development without waiting. It guides us setup DKIM, SPF, DMARC and BINI to increase reputation and guarentee the deliverability at each identity level.
$ aws sesv2 create-email-identity --email-identity mm-notes.com
{
"IdentityType": "DOMAIN",
"VerifiedForSendingStatus": false,
"DkimAttributes": {
"SigningEnabled": true,
"Status": "NOT_STARTED",
"Tokens": [
"token-1",
"token-2",
"token-3"
],
"SigningAttributesOrigin": "AWS_SES",
"NextSigningKeyLength": "RSA_2048_BIT",
"CurrentSigningKeyLength": "RSA_2048_BIT",
"LastKeyGenerationTimestamp": 1754653048.28
}
}
$ aws sesv2 get-email-identity --email-identity mm-notes.com
{
"IdentityType": "DOMAIN",
"FeedbackForwardingStatus": true,
"VerifiedForSendingStatus": false,
"DkimAttributes": {
"SigningEnabled": true,
"Status": "PENDING",
"Tokens": [
"token-1",
"token-2",
"token-3"
],
"SigningAttributesOrigin": "AWS_SES",
"NextSigningKeyLength": "RSA_2048_BIT",
"CurrentSigningKeyLength": "RSA_2048_BIT",
"LastKeyGenerationTimestamp": 1754653048.28
},
"MailFromAttributes": {
"BehaviorOnMxFailure": "USE_DEFAULT_VALUE"
},
"Policies": {},
"Tags": [],
"VerificationStatus": "PENDING",
"VerificationInfo": {}
}
Once SES identity created, it will be in Verification pending status.
To validate, we need to create TXT DNS records based on the Tokens under DkimAttributes.
These record value ends with dkim.amazonses.com.
If you are using AWS Route53 as your DNS, you may push a button Publish DNS records to Route53 on the console to publish. Alternatively you can download the record set and work with your DNS provider.
We have to wait for AWS to validate the DNS entries. Until then if we attempt sending email, we get error message like below.
dig CNAME token._domainkey.mm-notes.com
nslookup -type=CNAME token._domainkey.mm-notes.com
$ aws ses send-email \
--from "[email protected]" \
--destination "[email protected]" \
--message "Subject={Data=Test Email},Body={Text={Data=Hello World}}"
An error occurred (MessageRejected) when calling the SendEmail operation: Email address is not verified. The following identities failed the check in region US-EASTT-1: [email protected], [email protected]
Once the setup successful,
$ aws ses send-email \
> --from "[email protected]" \
> --destination "[email protected]" \
> --message "Subject={Data=Test Email},Body={Text={Data=Hello World}}"
{
"MessageId": "random-uuid-000000"
}
Suppression list is being built by SES over a period of time based on its attempt to deliver mails to target list. We can also import suppression list which is helpful if we have multiple environment and when needed to follow the “Unsubscribe / Do Not Distrub” guidelines.
While AWS console is not allowing to export all suppression list, we can export it with below python script. This is useful to share with business team to aware and act.
import boto3
import csv
from datetime import datetime
def get_ses_suppressions():
# Initialize SESv2 client for SES service region
ses_client = boto3.client('sesv2', region_name='us-east-1')
# Lists to store different types of suppressions
suppressions = []
# Get current timestamp for filename
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
try:
# Get all suppressed destinations with manual pagination using NextToken
next_token = None
while True:
# Prepare parameters for API call
params = {'Reasons': ['BOUNCE', 'COMPLAINT']}
if next_token:
params['NextToken'] = next_token
# Make API call
response = ses_client.list_suppressed_destinations(**params)
# Process results
for item in response.get('SuppressedDestinationSummaries', []):
suppressions.append({
'email': item['EmailAddress'],
'reason': item['Reason'],
'last_update_time': item['LastUpdateTime'].strftime('%Y-%m-%d %H:%M:%S'),
'attributes': str(item.get('Attributes', {}))
})
# Check if there are more results
next_token = response.get('NextToken')
if not next_token:
break
# Write to CSV file
output_file = f'ses_suppressions_{timestamp}.csv'
with open(output_file, 'w', newline='') as csvfile:
fieldnames = ['email', 'reason', 'last_update_time', 'attributes']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for suppression in suppressions:
writer.writerow(suppression)
print(f"Successfully exported {len(suppressions)} suppressions to {output_file}")
except Exception as e:
print(f"Error occurred: {str(e)}")
if __name__ == "__main__":
get_ses_suppressions()
We can also use AWS cli to periodically check new supressions
$ aws sesv2 list-suppressed-destinations --start-date $(date -d "14 days ago" +%s)
$ aws sesv2 create-export-job \
--export-data-source '{
"MessageInsightsDataSource": {
"StartDate": '$(date -d "1 days ago" +%s)',
"EndDate": '$(date +%s)',
"Include": {
"LastDeliveryEvent": ["PERMANENT_BOUNCE","TRANSIENT_BOUNCE", "COMPLAINT", "UNDETERMINED_BOUNCE"]
}
}
}' \
--export-destination '{
"DataFormat": "CSV"
}'
The above command will return an job-id. We can check the job detais with following command. When it completes, it will have a pre-signed url for the export. (Not in our AWS account - Security and Privacy?)
$ aws sesv2 get-export-job --job-id <your-job-id>
Single Sign On (SSO) is considered as a security best practice. Managing users and their access rights centrally help smooth and quick onboarding and offboarding employess in the organization. I wanted to share notes to enable this integration and strategy to implement few use cases.
As both Microsoft and AWS are favouring the need of SSO integration, the steps to integrate is getting easy as time passes. Here are steps and screenshots.
In technical terms, This integration uses SAML based SSO where Microsoft Entra ID act as IDP and AWS IAM Identity Center act as SP. AWS IAM Identity Center also accepting SCIM provisioing to keep User-Group setup in sync with Microsoft Entra ID.
Now you have successfully created the application.
IAM Identity Center act as SP which is allowed to configure only one IDP. By default it is using Identity Center Directory. We have to change it by going to Identity Ceter -> Settings –> Identity Source Actions -> Change identity source
Once you select External identity provider, you can download metadata file. If you are not managing IDP Entra ID, you should share this with respective team.
In Azure Portal, Entra ID –> Enterprise applications –> Go to the same application created in earlier setup –> Manage –> Single Sign-on – Upload (SP) Metadata file
Once you upload SP metadata, you can download Federation (IDP) Metadata XML.
If you dont manage AWS Identity Center, share it with respective team.
IDP metadata which is required to upload in the same change identiy source page in AWS console.
In Entra ID create security groups to represent the different teams which require AWS access.
Sample naming format:
where role can be developers, data scientists, architects, support etc.,
SCIM - System for Cross-domain Identity Management
While we(AWS) strongly recommend that you adopt the practices outlined in Organizing Your AWS Environment Using Multiple Accounts whitepaper, realistically customers often find themselves with mixed and complex account structures that take time to migrate away from. Implementing a rigorous and effective tagging strategy is the key in this scenario, followed by activating relevant tags for cost allocation in the Billing and Cost Management console (in AWS Organizations, tags can be activated for cost allocation only from the Management Payer account).
Once you defined the taging strategy, define cost allocation tags if the tag can answer any FINOPS questions.
AWS pricing pages has very detaild documentation with samples. However it takes time to understand and figure out what is the cost of our resource based on the option we have choosen while creating.
We can tag the cost factor in the tag based on the provision we have made. This creates awareness to the engineers. For example cost-factor: $16/month
Tag editor can be very useful to bulk edit tags to refactor existing tags or add tags by filtering resources.
Tagging existing infrastructure with 1000s of resources will be a overwhelming task. Especially if the resources are not part of infrastructure as code. If you can derive the tag values based on existing attributes or names of the resource, then we could write program to select the resource with filtering and apply tags programatically. Here are few python example bulk tag examples.
import boto3
import logging
# Configure logging
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
def list_vpc_endpoints(region_name):
"""
Lists all VPC endpoints in a given AWS region.
Args:
region_name (str): The AWS region to list VPC endpoints in (e.g., 'us-east-1').
Returns:
list: A list of dictionaries, where each dictionary represents a VPC endpoint.
Returns an empty list if no VPC endpoints are found or if an error occurs.
"""
try:
# Create an EC2 client for the specified region
ec2_client = boto3.client('ec2', region_name=region_name)
# Describe VPC endpoints
response = ec2_client.describe_vpc_endpoints()
# Extract VPC endpoint information
vpc_endpoints = response.get('VpcEndpoints', []) # Safe handling if 'VpcEndpoints' key is missing
if vpc_endpoints:
logging.info(f"Found {len(vpc_endpoints)} VPC endpoints in region {region_name}.")
return vpc_endpoints
else:
logging.info(f"No VPC endpoints found in region {region_name}.")
return []
except Exception as e:
logging.error(f"An error occurred: {e}")
return []
def tag_vpc_endpoint(region_name, endpoint_id, endpoint_service_name):
"""
Tags a VPC endpoint with the tag "app-name" and the endpoint name as the tag value.
Args:
region_name (str): The AWS region where the VPC endpoint exists.
endpoint_id (str): The ID of the VPC endpoint to tag.
endpoint_service_name (str): The desired name for the endpoint to be used as the tag value.
"""
try:
ec2_client = boto3.client('ec2', region_name=region_name)
tags = [{
'Key': 'service-name',
'Value': endpoint_service_name
},
{
'Key': 'resource-type',
'Value': 'vpc-endpoint'
},
{
'Key': 'approx-cost',
'Value': '$16/month' # modify based on your observation/calculation
}]
ec2_client.create_tags(Resources=[endpoint_id], Tags=tags)
logging.info(f"Successfully tagged VPC endpoint {endpoint_id} with app-name:{endpoint_service_name}")
except Exception as e:
logging.error(f"Error tagging VPC endpoint {endpoint_id}: {e}")
def main():
"""
Main function to list VPC endpoints and tag them.
"""
region = input("Enter the AWS region (e.g., us-east-1): ")
if not region:
print("Region cannot be empty. Please provide a valid AWS region.")
return
vpc_endpoints = list_vpc_endpoints(region)
if vpc_endpoints:
print("\nVPC Endpoints:")
for endpoint in vpc_endpoints:
endpoint_id = endpoint['VpcEndpointId']
endpoint_service_name = endpoint.get('ServiceName', 'UnknownEndpoint') #Default value if ServiceName is empty
print("------------------------------------")
print(f"VPC Endpoint ID: {endpoint_id}")
print(f"VPC ID: {endpoint['VpcId']}")
print(f"Service Name: {endpoint['ServiceName']}")
print(f"State: {endpoint['State']}")
print(f"Creation Timestamp: {endpoint['CreationTimestamp']}")
# Tag the VPC endpoint
tag_vpc_endpoint(region, endpoint_id, endpoint_service_name)
else:
print(f"No VPC endpoints found or an error occurred in region {region}.")
if __name__ == "__main__":
main()
import boto3
sts_client = boto3.client('sts') # Create STS client
account_id = sts_client.get_caller_identity()['Account']
print(account_id)
def tag_dynamodb_tables():
"""Tags all DynamoDB tables with the 'app-name' tag,
using the table name as the tag value.
"""
dynamodb = boto3.client('dynamodb')
tables = getAllTableByPaginating(dynamodb)
tagTables(dynamodb, tables)
def getAllTableByPaginating(dynamodb):
table_names = []
last_evaluated_table_name = ''
try:
# List all DynamoDB tables using pagination
while True:
if last_evaluated_table_name:
response = dynamodb.list_tables(ExclusiveStartTableName=last_evaluated_table_name)
else:
response = dynamodb.list_tables()
table_names.extend(response.get('TableNames', []))
last_evaluated_table_name = response.get('LastEvaluatedTableName')
if not last_evaluated_table_name:
break
except Exception as e:
print(f"Error listing tables: {e}")
return []
return table_names
def tagTables(dynamodb, tables):
for table_name in tables:
try:
# Check if the table already has the 'app-name' tag. This avoids unnecessary API calls.
existing_tags = dynamodb.list_tags_of_resource(
ResourceArn=f'arn:aws:dynamodb:{boto3.session.Session().region_name}:{account_id}:table/{table_name}'
)
app_name_tag_exists = False
if 'Tags' in existing_tags:
for tag in existing_tags['Tags']:
if tag['Key'] == 'app-name':
app_name_tag_exists = True
break
if not app_name_tag_exists: # Only tag if it doesn't exist.
# Tag the table
dynamodb.tag_resource(
ResourceArn=f'arn:aws:dynamodb:{boto3.session.Session().region_name}:{account_id}:table/{table_name}',
Tags=[
{
'Key': 'app-name',
'Value': table_name
},
]
)
print(f"Tagged table: {table_name}")
else:
print(f"Table {table_name} already has the app-name tag. Skipping.")
except Exception as e:
print(f"Error tagging table {table_name}: {e}")
if __name__ == "__main__":
tag_dynamodb_tables()
import boto3
def tag_workspaces():
"""
Lists all AWS WorkSpaces and adds a tag with Key='primary-owner' and Value equal to the Workspace's username.
Prerequisites:
- The IAM role/user running this script needs permission for:
workspaces:DescribeWorkspaces
workspaces:CreateTags
"""
try:
workspaces = boto3.client('workspaces')
all_workspaces = []
next_token = ''
while True:
if next_token:
response = workspaces.describe_workspaces(NextToken=next_token)
else:
response = workspaces.describe_workspaces()
workspaces_data = response.get('Workspaces', [])
for workspace in workspaces_data:
workspace_id = workspace.get('WorkspaceId')
username = workspace.get('UserName')
if workspace_id and username:
try:
# Tag the workspace
workspaces.create_tags(
ResourceId=workspace_id,
Tags=[
{
'Key': 'primary-owner',
'Value': username
}
]
)
print(f"Successfully tagged Workspace '{workspace_id}' with primary-owner='{username}'")
except Exception as tag_err:
print(f"Error tagging Workspace '{workspace_id}': {tag_err}")
next_token = response.get('NextToken')
if not next_token:
break
except Exception as e:
print(f"Error listing or tagging WorkSpaces: {e}")
if __name__ == "__main__":
tag_workspaces()
Google offers free services for nominal use for both personal and business purpose. For businesses who wants to have their own office workspace solution (like Microsoft O365), google offers GSuite. But it
Often businesses needs to share Google services (ex: GDrive) to outside organization. At the sametime not to allow personal accounts (with gmail domain) from accessing the business documents/resources.
Also it is good not to use personal accounts and avoid mixing personal and business documents, it is recommended getting separate google account.Even better, create a google account so your business partners can simply use your business mail address to share their google storage contents and collaborate.
Configure global setting for Google Shared Drive based on the need.
https://admin.google.com/ac/domains/allowlisted
Logout previously logged in google accounts or open browser in “private browsing / incognito” mode

At the sign in screen, follow create account flow. Choose “For work or my business”

Fill the required fields

Google recommends few email address with gmail domain. Because we want to use our business email based google account, select User your existing email

Provide work mail address

Verify the ownership of the email you provided

Create password

Confirm the ownership of MFA device


Individual shared drive members and access can be setup under managedrive settings.


To list all manual and automated Redshift snapshots created in the last 30 days:
aws redshift describe-cluster-snapshots \
--snapshot-type manual \
--start-time $(date -v-365d +"%Y-%m-%dT%H:%M:%S")
To limit few fiels with jq
aws redshift describe-cluster-snapshots | jq ".Snapshots[] | {SnapshotIdentifier, ClusterIdentifier, SnapshotCreateTime, SnapshotType, TotalBackupSizeInMegaBytes, ManualSnapshotRetentionPeriod}"
List snapshots without retention period
$ aws redshift describe-cluster-snapshots --snapshot-type manual,automated --no-retention-period
--no-retention-period is NOT working as Amazon Q explains or unofficial blog posts. It is not implemented
$ aws redshift describe-cluster-snapshots --snapshot-type manual | jq ".Snapshots |= map(select (.ManualSnapshotRetentionPeriod == -1))" | jq ".Snapshots[] | {SnapshotIdentifier, ClusterIdentifier, SnapshotCreateTime, SnapshotType, TotalBackupSizeInMegaBytes, ManualSnapshotRetentionPeriod}"
To view snapshot schedules
$ aws redshift describe-snapshot-schedules
Node Types
dc2.largera3aws redshift describe-clusters | jq ".Clusters[] |= {ClusterIdentifier,NodeType, ClusterStatus }"
Before making any infrastructure or DBA kind changes, it is recommended to take backup.
aws redshift create-cluster-snapshot --cluster-identifier <cluster-name> --snapshot-identifier <snapshot-name> [--snapshot-cluster-identifier <cluster-name>]
aws redshift create-cluster-snapshot --cluster-identifier myredshift-sandbox --snapshot-identifier myredshift-sandbox-001
create table driver (name VARCHAR, age integer, candrivecar boolean);
insert into driver values ('Mahendran', 55, true);
Manipulate sample DB
select * from users limit 10
delete from users where username = 'AEB55QTM'
select * from users where username = 'AEB55QTM'
aws redshift create-cluster-snapshot --cluster-identifier myredshift-sandbox --snapshot-identifier myredshift-sandbox-after-change
$ aws redshift pause-cluster --cluster-identifier <cluster-name>
$ aws redshift pause-cluster --cluster-identifier myredshift-sandbox
$ aws redshift describe-clusters | jq ".Clusters[] |= {ClusterIdentifier,NodeType, ClusterStatus }"
{
"Clusters": [
{
"ClusterIdentifier": "myredshift-sandbox",
"NodeType": "dc2.large",
"ClusterStatus": "pausing"
}
]
}
$ aws redshift describe-clusters | jq ".Clusters[] |= {ClusterIdentifier,NodeType, ClusterStatus }"
{
"Clusters": [
{
"ClusterIdentifier": "myredshift-sandbox",
"NodeType": "dc2.large",
"ClusterStatus": "paused"
}
]
}
$ aws redshift describe-events --source-identifier myredshift-sandbox --source-type cluster
$ aws redshift resume-cluster --cluster-identifier <cluster-name>
$ aws redshift resume-cluster --cluster-identifier myredshift-sandbox
$ aws redshift describe-clusters | jq ".Clusters[] |= {ClusterIdentifier,NodeType, ClusterStatus }"
{
"Clusters": [
{
"ClusterIdentifier": "myredshift-sandbox",
"NodeType": "dc2.large",
"ClusterStatus": "resuming"
}
]
}
$ aws redshift describe-clusters | jq ".Clusters[] |= {ClusterIdentifier,NodeType, ClusterStatus }"
{
"Clusters": [
{
"ClusterIdentifier": "myredshift-sandbox",
"NodeType": "dc2.large",
"ClusterStatus": "available"
}
]
}
Delete cluster using console to confirm after reviewing. Paused cluster can be deleted; Create final snapshot to avoid data loss.
$ aws redshift describe-cluster-snapshots --snapshot-type manual | jq ".Snapshots |= map(select (.ManualSnapshotRetentionPeriod == -1))" | jq ".Snapshots[] | {SnapshotIdentifier, ClusterIdentifier, SnapshotCreateTime, SnapshotType, TotalBackupSizeInMegaBytes, ManualSnapshotRetentionPeriod}"
{
"SnapshotIdentifier": "myredshift-sandbox-final-snapshot",
"ClusterIdentifier": "myredshift-sandbox",
"SnapshotCreateTime": "2024-08-26T22:19:17.623000+00:00",
"SnapshotType": "manual",
"TotalBackupSizeInMegaBytes": 4206,
"ManualSnapshotRetentionPeriod": -1
}
{
"SnapshotIdentifier": "myredshift-sandbox-after-change",
"ClusterIdentifier": "myredshift-sandbox",
"SnapshotCreateTime": "2024-08-26T21:59:49.967000+00:00",
"SnapshotType": "manual",
"TotalBackupSizeInMegaBytes": 3931,
"ManualSnapshotRetentionPeriod": -1
}
{
"SnapshotIdentifier": "myredshift-sandbox-001",
"ClusterIdentifier": "myredshift-sandbox",
"SnapshotCreateTime": "2024-08-26T21:45:05.894000+00:00",
"SnapshotType": "manual",
"TotalBackupSizeInMegaBytes": 707,
"ManualSnapshotRetentionPeriod": -1
}
$ aws redshift restore-from-cluster-snapshot \
--snapshot-identifier myredshift-sandbox-final-snapshot \
--cluster-identifier myredshift-sandbox-new \
--node-type dc2.large \
--allow-version-upgrade
$ aws redshift describe-clusters | jq ".Clusters[] |= {ClusterIdentifier,NodeType, ClusterStatus }"
{
"Clusters": [
{
"ClusterIdentifier": "myredshift-sandbox-new",
"NodeType": "dc2.large",
"ClusterStatus": "creating"
}
]
}
While restoring from snapshot, we can change the cluster configuration. To find what options available…
aws redshift describe-node-configuration-options --snapshot-identifier myredshift-sandbox-final-snapshot --region eu-west-1 --action-type restore-cluster
$ aws redshift restore-from-cluster-snapshot --snapshot-identifier as-is-as-of-aug-23 --cluster-identifier mysandbox-3 --node-type dc2.large --allow-version-upgrade
An error occurred (InvalidSubnet) when calling the RestoreFromClusterSnapshot operation: No default subnet detected in VPC. Please contact AWS Support to recreate default Subnets.
To make/block the cluster accessible from internet (outside VPC), change the cluster properties –> Network and security settings
–> Publicly accessible settings
To make/block the serverless workgroup accessible from internet (outside VPC), go to your workgroup and edit Data access –> Publicly accessible settings
select * from pg_user;
CREATE USER awsdbuser WITH PASSWORD 'YourSecurePassword';
GRANT ROLE sys:dba TO awsdbuser;
GRANT ROLE sys:superuser TO awsdbuser;
select * from pg_user;
If you dont have business problem, then you can’t possibiliy come up with machine learning algorithm and model to answer what you are trying figure out.
Model is a trained algorithm which is
Learn by identifying data that is already been labeled. We have/had data to train
Classification:
There is no existing data points to train. We just have raw data. The machine has to uncover and create the labels itself.
Learning through trial and error.
Why/When do we need VPC?
AWS RegionAWS Region.Avalability Zones within the Region.AvailabilityZoneId (ex: use1-az1) associated with a physical location which is common for all AWS account. This is best to compare if we ever work with two different accounts/partners.Resource map.aws ec2 describe-vpcs
aws ec2 describe-internet-gateways
aws ec2 describe-subnets
Aleternatively, use ELB with with public NAT gateway.
Because enabling VPC logs will incur cost, it is recommended to identify the need and proper process in place to ensure the logs are monitored or audited. It is important to let the stakeholders involved. Depends on the stakeholder commitment we should enable right level of logging.
$ atlas auth login
$ atlas setup --clusterName myAtlasClusterEDU --provider AWS --currentIp --skipSampleData --username myAtlasDBUser --password myatlas-001 | tee atlas_cluster_details.txt
$ atlas clusters sampleData load myAtlasClusterEDU
vi /etc/mondod.conf
security:
authorization: enabled
mongod --config /etc/mongod.conf
mongosh localhost:27017/admin
> use admin
> db.createUser(...)
> db.getUsers()
https://learn.mongodb.com/learn/course/mongodb-self-managed-database-security/lesson-3-establishing-authorization-for-a-self-managed-mongodb-deployment/learn?client=customer&page=2
db.createUser(
{
user: "financeUser",
pwd: passwordPrompt(),
roles: [
{ role: "readWrite", db: "sample_analytics" },
{ role: "read", db: "sample_supplies" }
]
}
)
mongosh "mongodb://analyst@localhost:27017/sample_analytics?authSource=admin"
db.revokeRolesFromUser(
"financeUser",
[
{
role: "read",
db: "sample_supplies"
}
]
)
mongosh localhost:27017/admin –username globalUserAdmin
https://learn.mongodb.com/learn/course/mongodb-self-managed-database-security/lesson-4-security-auditing-in-mongodb/learn?client=customer&page=2
/etc/mondod.conf under auditLog section.jq for pretty print. sudo tail /var/log/mongodb/auditLog.json | jqTLS certificate for each server in a deployment to enable TLS in a self-managed environment. You also learned that the net.tls.mode configuration file setting must be set to requireTLS to specify that a server uses and accepts only TLS-encrypted connections.
https://learn.mongodb.com/learn/course/mongodb-self-managed-database-security/lesson-7-enabling-network-encryption-for-a-self-managed-mongodb-deployment/learn?client=customer&page=2
.pem file formathttps://learn.mongodb.com/learn/course/mongodb-atlas-security/lesson-1-introduction-to-security/learn
atlas projects list --orgID 1234
atlas projects organizations invitations invite ...
atlas projects users list
atlas projects user delete ...
https://learn.mongodb.com/learn/course/mongodb-atlas-security/lesson-3-atlas-user-management/learn?client=customer&page=2
root@mongodb:~$ atlas projects invitations invite [email protected] --role GROUP_READ_ONLY
root@mongodb:~$ atlas projects invitations list
ID USERNAME CREATED AT EXPIRES AT
65dc68f235aac70ddc602409 [email protected] 2024-02-26 10:33:22 +0000 UTC 2024-03-27 10:33:22 +0000 UTC
root@mongodb:~$ atlas organizations invitations list --orgId 1234567890
ID USERNAME CREATED AT EXPIRES AT
65dc68f235aac70ddc602409 [email protected] 2024-02-26 10:33:22 +0000 UTC 2024-03-27 10:33:22 +0000 UTC
root@mongodb:~$ atlas project invitations delete 65dc68f235aac70ddc602409
? Are you sure you want to delete: 65dc68f235aac70ddc602409 Yes
Invitation '65dc68f235aac70ddc602409' deleted
root@mongodb:~$ atlas organizations invitations list --orgId 1234567890
ID USERNAME CREATED AT EXPIRES AT