Blog

Coders Conquer Security Infrastructure as Code Series: Plaintext Storage of Passwords

Matias Madou, Ph.D.
Published May 18, 2020

When it comes to deploying secure infrastructure as code in your own organization, how are you doing? It might be somewhat of a learning curve, but learning the ropes will be a great chance to level up your skillset, stand out among your peers, and keep more end-user data safe.

Before we get started on this next chapter of our latest Coders Conquer Security series, I'd like to invite you to play a gamified challenge of the sensitive data storage vulnerability; play now and choose from Kubernetes, Terraform, Ansible, Docker, or CloudFormation:

How was that? If your knowledge needs some work, read on:

The key to most computer security these days involves passwords. Even if other security methods are employed, like two-factor authentication or biometrics, most organizations still employ password-based security as one element of their protection. For many companies, passwords are exclusively used.

We use passwords so much that we even have rules about how to create them. This is supposed to make them less vulnerable to brute force attacks or even wild guessing. Of course, some people still use weak passwords, as evidenced in a recent report from NordPass. It's hard to believe that in 2020 people are still using 12345 as well as a bunch of other guessable words like chocolate, password and God to protect their most sensitive assets.

There will always be those who don't care to use strong passwords, but most professional organizations will force users to craft their access words or phrases in certain ways. We all know the rules by now with passwords needing to be at least eight characters and comprised of both capital and lower case letters with at least one number and a special character required.

The bad thing is that even if users adhere to the rules for making the strongest kinds of passwords, it may not do any good if they are all stored in plaintext. The password 12345 is just as bad as Nuts53!SpiKe&Dog12 if a hacker is able to read the entire password file.

Why is storing passwords in plaintext dangerous?

Storing passwords in plaintext is bad because it puts both the system and users at risk. Obviously, having a hacker able to find and read every single password used to access a system would be a disaster. They could simply find a user with administrator credentials and compromise the entire system or site. And because they would be utilizing proper user names and passwords, internal security may not catch the intrusion or catch it long after the damage is done.

Making it easy for attackers to steal passwords stored in plaintext also hurts users, because many people reuse passwords. Because we have made passwords so difficult to create, a lot of people resort to reusing ones that they can remember on multiple sites. If an attacker compromises a password file, they will almost certainly try to access other systems using the same name and password, which puts users at great risk of secondary crimes.

It's relatively easy to accidentally store passwords in plain text or not realize that this could cause major problems down the road. For example, the following code is a common method employed to store passwords when defining an AWS resource using Terraform templates:

resource "aws_db_instance" "default" {
 engine                 = "mysql"
 allocated_storage      = 10
 instance_class         = "db.t2.micro"
 username               = "admin"
 password               = "s3.cr3t.admin.p2ss"
 db_subnet_group_name   = aws_db_subnet_group.default.name
 vpc_security_group_ids = [aws_security_group.default.id]
}

In that example, the password used to manage the MySQL database instance in AWS is being stored in plaintext. That means that anyone with access to the source code repository could read, or even copy it.

Protecting passwords varies depending on the framework, but protection methods exist for every platform. For example, MySQL password can be stored in a  secure storage like AWS Secrets Manager:

resource "aws_db_instance" "default" {
 engine            = "mysql"
 allocated_storage = 10
 instance_class    = "db.t2.micro"
 username          = "admin"
 password = "${data.aws_secretsmanager_secret_version.password.secret_string}"
 db_subnet_group_name   = aws_db_subnet_group.default.name
 vpc_security_group_ids = [aws_security_group.default.id]
}

In that example, the Terraform template will get the password from AWS Secrets Manager service and it will never be stored in plaintext in template files.

Protecting passwords by avoiding plaintext storage

Passwords are the keys to your kingdom and should never be stored in plaintext. Even those internal to an organization shouldn't have access to a big, unprotected repository of passwords, nor should this be an accepted business protocol (there are plenty of password managers that allow encrypted credential sharing these days - no excuses!). There is also the danger of malicious insiders snooping files and gaining access where they shouldn't.

And with an outside attack, just imagine the double-whammy that is possible if a back door to your database is found through something as simple as a SQL injection vulnerability, and they gain access to the directory where the passwords are stored as well. Think this is too many error-laden steps to come to fruition? Sadly, this exact scenario happened in Sony's 2011 breach. Over one million customer passwords were stored in plaintext, and the Lulzsec hacking group accessed those and much more through a common SQL injection attack.

All passwords should be protected by whatever defenses are available within the supporting framework. For Terraform, passwords should never be stored in template files. It is recommended to use secure storage like AWS Secrets Manager or Azure Key Vault, depending on the infrastructure provider.

Forcing users to create secure passwords is a good idea, but then you need to do your part on the backend as well. Keeping passwords out of plaintext storage will go a long way to protecting your users and your systems. The main danger of plaintext password storage is the poor access control; essentially, anyone can see them. It's imperative (especially in an IaC environment where suddenly, more people have access to sensitive information) that they are adequately hashed and only those who absolutely require access are granted it.

Check out the Secure Code Warrior blog pages for more insight about this vulnerability and how to protect your organization and your customers from the ravages of other security flaws and vulnerabilities. You can also try a demo IaC challenge within the Secure Code Warrior training platform to keep all your cybersecurity skills honed and up to date.


View Resource
View Resource

The key to most computer security these days involves passwords. Even if other security methods are employed, like two-factor authentication or biometrics, most organizations still employ password-based security as one element of their protection.

Interested in more?

Matias Madou, Ph.D. is a security expert, researcher, and CTO and co-founder of Secure Code Warrior. Matias obtained his Ph.D. in Application Security from Ghent University, focusing on static analysis solutions. He later joined Fortify in the US, where he realized that it was insufficient to solely detect code problems without aiding developers in writing secure code. This inspired him to develop products that assist developers, alleviate the burden of security, and exceed customers' expectations. When he is not at his desk as part of Team Awesome, he enjoys being on stage presenting at conferences including RSA Conference, BlackHat and DefCon.

Secure Code Warrior is here for your organization to help you secure code across the entire software development lifecycle and create a culture in which cybersecurity is top of mind. Whether you’re an AppSec Manager, Developer, CISO, or anyone involved in security, we can help your organization reduce risks associated with insecure code.

Book a demo
Share on:
Author
Matias Madou, Ph.D.
Published May 18, 2020

Matias Madou, Ph.D. is a security expert, researcher, and CTO and co-founder of Secure Code Warrior. Matias obtained his Ph.D. in Application Security from Ghent University, focusing on static analysis solutions. He later joined Fortify in the US, where he realized that it was insufficient to solely detect code problems without aiding developers in writing secure code. This inspired him to develop products that assist developers, alleviate the burden of security, and exceed customers' expectations. When he is not at his desk as part of Team Awesome, he enjoys being on stage presenting at conferences including RSA Conference, BlackHat and DefCon.

Matias is a researcher and developer with more than 15 years of hands-on software security experience. He has developed solutions for companies such as Fortify Software and his own company Sensei Security. Over his career, Matias has led multiple application security research projects which have led to commercial products and boasts over 10 patents under his belt. When he is away from his desk, Matias has served as an instructor for advanced application security training courses and regularly speaks at global conferences including RSA Conference, Black Hat, DefCon, BSIMM, OWASP AppSec and BruCon.

Matias holds a Ph.D. in Computer Engineering from Ghent University, where he studied application security through program obfuscation to hide the inner workings of an application.

Share on:

When it comes to deploying secure infrastructure as code in your own organization, how are you doing? It might be somewhat of a learning curve, but learning the ropes will be a great chance to level up your skillset, stand out among your peers, and keep more end-user data safe.

Before we get started on this next chapter of our latest Coders Conquer Security series, I'd like to invite you to play a gamified challenge of the sensitive data storage vulnerability; play now and choose from Kubernetes, Terraform, Ansible, Docker, or CloudFormation:

How was that? If your knowledge needs some work, read on:

The key to most computer security these days involves passwords. Even if other security methods are employed, like two-factor authentication or biometrics, most organizations still employ password-based security as one element of their protection. For many companies, passwords are exclusively used.

We use passwords so much that we even have rules about how to create them. This is supposed to make them less vulnerable to brute force attacks or even wild guessing. Of course, some people still use weak passwords, as evidenced in a recent report from NordPass. It's hard to believe that in 2020 people are still using 12345 as well as a bunch of other guessable words like chocolate, password and God to protect their most sensitive assets.

There will always be those who don't care to use strong passwords, but most professional organizations will force users to craft their access words or phrases in certain ways. We all know the rules by now with passwords needing to be at least eight characters and comprised of both capital and lower case letters with at least one number and a special character required.

The bad thing is that even if users adhere to the rules for making the strongest kinds of passwords, it may not do any good if they are all stored in plaintext. The password 12345 is just as bad as Nuts53!SpiKe&Dog12 if a hacker is able to read the entire password file.

Why is storing passwords in plaintext dangerous?

Storing passwords in plaintext is bad because it puts both the system and users at risk. Obviously, having a hacker able to find and read every single password used to access a system would be a disaster. They could simply find a user with administrator credentials and compromise the entire system or site. And because they would be utilizing proper user names and passwords, internal security may not catch the intrusion or catch it long after the damage is done.

Making it easy for attackers to steal passwords stored in plaintext also hurts users, because many people reuse passwords. Because we have made passwords so difficult to create, a lot of people resort to reusing ones that they can remember on multiple sites. If an attacker compromises a password file, they will almost certainly try to access other systems using the same name and password, which puts users at great risk of secondary crimes.

It's relatively easy to accidentally store passwords in plain text or not realize that this could cause major problems down the road. For example, the following code is a common method employed to store passwords when defining an AWS resource using Terraform templates:

resource "aws_db_instance" "default" {
 engine                 = "mysql"
 allocated_storage      = 10
 instance_class         = "db.t2.micro"
 username               = "admin"
 password               = "s3.cr3t.admin.p2ss"
 db_subnet_group_name   = aws_db_subnet_group.default.name
 vpc_security_group_ids = [aws_security_group.default.id]
}

In that example, the password used to manage the MySQL database instance in AWS is being stored in plaintext. That means that anyone with access to the source code repository could read, or even copy it.

Protecting passwords varies depending on the framework, but protection methods exist for every platform. For example, MySQL password can be stored in a  secure storage like AWS Secrets Manager:

resource "aws_db_instance" "default" {
 engine            = "mysql"
 allocated_storage = 10
 instance_class    = "db.t2.micro"
 username          = "admin"
 password = "${data.aws_secretsmanager_secret_version.password.secret_string}"
 db_subnet_group_name   = aws_db_subnet_group.default.name
 vpc_security_group_ids = [aws_security_group.default.id]
}

In that example, the Terraform template will get the password from AWS Secrets Manager service and it will never be stored in plaintext in template files.

Protecting passwords by avoiding plaintext storage

Passwords are the keys to your kingdom and should never be stored in plaintext. Even those internal to an organization shouldn't have access to a big, unprotected repository of passwords, nor should this be an accepted business protocol (there are plenty of password managers that allow encrypted credential sharing these days - no excuses!). There is also the danger of malicious insiders snooping files and gaining access where they shouldn't.

And with an outside attack, just imagine the double-whammy that is possible if a back door to your database is found through something as simple as a SQL injection vulnerability, and they gain access to the directory where the passwords are stored as well. Think this is too many error-laden steps to come to fruition? Sadly, this exact scenario happened in Sony's 2011 breach. Over one million customer passwords were stored in plaintext, and the Lulzsec hacking group accessed those and much more through a common SQL injection attack.

All passwords should be protected by whatever defenses are available within the supporting framework. For Terraform, passwords should never be stored in template files. It is recommended to use secure storage like AWS Secrets Manager or Azure Key Vault, depending on the infrastructure provider.

Forcing users to create secure passwords is a good idea, but then you need to do your part on the backend as well. Keeping passwords out of plaintext storage will go a long way to protecting your users and your systems. The main danger of plaintext password storage is the poor access control; essentially, anyone can see them. It's imperative (especially in an IaC environment where suddenly, more people have access to sensitive information) that they are adequately hashed and only those who absolutely require access are granted it.

Check out the Secure Code Warrior blog pages for more insight about this vulnerability and how to protect your organization and your customers from the ravages of other security flaws and vulnerabilities. You can also try a demo IaC challenge within the Secure Code Warrior training platform to keep all your cybersecurity skills honed and up to date.


View Resource
View Resource

Fill out the form below to download the report

We would like your permission to send you information on our products and/or related secure coding topics. We’ll always treat your personal details with the utmost care and will never sell them to other companies for marketing purposes.

Submit
To submit the form, please enable 'Analytics' cookies. Feel free to disable them again once you're done.

When it comes to deploying secure infrastructure as code in your own organization, how are you doing? It might be somewhat of a learning curve, but learning the ropes will be a great chance to level up your skillset, stand out among your peers, and keep more end-user data safe.

Before we get started on this next chapter of our latest Coders Conquer Security series, I'd like to invite you to play a gamified challenge of the sensitive data storage vulnerability; play now and choose from Kubernetes, Terraform, Ansible, Docker, or CloudFormation:

How was that? If your knowledge needs some work, read on:

The key to most computer security these days involves passwords. Even if other security methods are employed, like two-factor authentication or biometrics, most organizations still employ password-based security as one element of their protection. For many companies, passwords are exclusively used.

We use passwords so much that we even have rules about how to create them. This is supposed to make them less vulnerable to brute force attacks or even wild guessing. Of course, some people still use weak passwords, as evidenced in a recent report from NordPass. It's hard to believe that in 2020 people are still using 12345 as well as a bunch of other guessable words like chocolate, password and God to protect their most sensitive assets.

There will always be those who don't care to use strong passwords, but most professional organizations will force users to craft their access words or phrases in certain ways. We all know the rules by now with passwords needing to be at least eight characters and comprised of both capital and lower case letters with at least one number and a special character required.

The bad thing is that even if users adhere to the rules for making the strongest kinds of passwords, it may not do any good if they are all stored in plaintext. The password 12345 is just as bad as Nuts53!SpiKe&Dog12 if a hacker is able to read the entire password file.

Why is storing passwords in plaintext dangerous?

Storing passwords in plaintext is bad because it puts both the system and users at risk. Obviously, having a hacker able to find and read every single password used to access a system would be a disaster. They could simply find a user with administrator credentials and compromise the entire system or site. And because they would be utilizing proper user names and passwords, internal security may not catch the intrusion or catch it long after the damage is done.

Making it easy for attackers to steal passwords stored in plaintext also hurts users, because many people reuse passwords. Because we have made passwords so difficult to create, a lot of people resort to reusing ones that they can remember on multiple sites. If an attacker compromises a password file, they will almost certainly try to access other systems using the same name and password, which puts users at great risk of secondary crimes.

It's relatively easy to accidentally store passwords in plain text or not realize that this could cause major problems down the road. For example, the following code is a common method employed to store passwords when defining an AWS resource using Terraform templates:

resource "aws_db_instance" "default" {
 engine                 = "mysql"
 allocated_storage      = 10
 instance_class         = "db.t2.micro"
 username               = "admin"
 password               = "s3.cr3t.admin.p2ss"
 db_subnet_group_name   = aws_db_subnet_group.default.name
 vpc_security_group_ids = [aws_security_group.default.id]
}

In that example, the password used to manage the MySQL database instance in AWS is being stored in plaintext. That means that anyone with access to the source code repository could read, or even copy it.

Protecting passwords varies depending on the framework, but protection methods exist for every platform. For example, MySQL password can be stored in a  secure storage like AWS Secrets Manager:

resource "aws_db_instance" "default" {
 engine            = "mysql"
 allocated_storage = 10
 instance_class    = "db.t2.micro"
 username          = "admin"
 password = "${data.aws_secretsmanager_secret_version.password.secret_string}"
 db_subnet_group_name   = aws_db_subnet_group.default.name
 vpc_security_group_ids = [aws_security_group.default.id]
}

In that example, the Terraform template will get the password from AWS Secrets Manager service and it will never be stored in plaintext in template files.

Protecting passwords by avoiding plaintext storage

Passwords are the keys to your kingdom and should never be stored in plaintext. Even those internal to an organization shouldn't have access to a big, unprotected repository of passwords, nor should this be an accepted business protocol (there are plenty of password managers that allow encrypted credential sharing these days - no excuses!). There is also the danger of malicious insiders snooping files and gaining access where they shouldn't.

And with an outside attack, just imagine the double-whammy that is possible if a back door to your database is found through something as simple as a SQL injection vulnerability, and they gain access to the directory where the passwords are stored as well. Think this is too many error-laden steps to come to fruition? Sadly, this exact scenario happened in Sony's 2011 breach. Over one million customer passwords were stored in plaintext, and the Lulzsec hacking group accessed those and much more through a common SQL injection attack.

All passwords should be protected by whatever defenses are available within the supporting framework. For Terraform, passwords should never be stored in template files. It is recommended to use secure storage like AWS Secrets Manager or Azure Key Vault, depending on the infrastructure provider.

Forcing users to create secure passwords is a good idea, but then you need to do your part on the backend as well. Keeping passwords out of plaintext storage will go a long way to protecting your users and your systems. The main danger of plaintext password storage is the poor access control; essentially, anyone can see them. It's imperative (especially in an IaC environment where suddenly, more people have access to sensitive information) that they are adequately hashed and only those who absolutely require access are granted it.

Check out the Secure Code Warrior blog pages for more insight about this vulnerability and how to protect your organization and your customers from the ravages of other security flaws and vulnerabilities. You can also try a demo IaC challenge within the Secure Code Warrior training platform to keep all your cybersecurity skills honed and up to date.


Access resource

Click on the link below and download the PDF of this resource.

Secure Code Warrior is here for your organization to help you secure code across the entire software development lifecycle and create a culture in which cybersecurity is top of mind. Whether you’re an AppSec Manager, Developer, CISO, or anyone involved in security, we can help your organization reduce risks associated with insecure code.

View reportBook a demo
Download PDF
View Resource
Share on:
Interested in more?

Share on:
Author
Matias Madou, Ph.D.
Published May 18, 2020

Matias Madou, Ph.D. is a security expert, researcher, and CTO and co-founder of Secure Code Warrior. Matias obtained his Ph.D. in Application Security from Ghent University, focusing on static analysis solutions. He later joined Fortify in the US, where he realized that it was insufficient to solely detect code problems without aiding developers in writing secure code. This inspired him to develop products that assist developers, alleviate the burden of security, and exceed customers' expectations. When he is not at his desk as part of Team Awesome, he enjoys being on stage presenting at conferences including RSA Conference, BlackHat and DefCon.

Matias is a researcher and developer with more than 15 years of hands-on software security experience. He has developed solutions for companies such as Fortify Software and his own company Sensei Security. Over his career, Matias has led multiple application security research projects which have led to commercial products and boasts over 10 patents under his belt. When he is away from his desk, Matias has served as an instructor for advanced application security training courses and regularly speaks at global conferences including RSA Conference, Black Hat, DefCon, BSIMM, OWASP AppSec and BruCon.

Matias holds a Ph.D. in Computer Engineering from Ghent University, where he studied application security through program obfuscation to hide the inner workings of an application.

Share on:

When it comes to deploying secure infrastructure as code in your own organization, how are you doing? It might be somewhat of a learning curve, but learning the ropes will be a great chance to level up your skillset, stand out among your peers, and keep more end-user data safe.

Before we get started on this next chapter of our latest Coders Conquer Security series, I'd like to invite you to play a gamified challenge of the sensitive data storage vulnerability; play now and choose from Kubernetes, Terraform, Ansible, Docker, or CloudFormation:

How was that? If your knowledge needs some work, read on:

The key to most computer security these days involves passwords. Even if other security methods are employed, like two-factor authentication or biometrics, most organizations still employ password-based security as one element of their protection. For many companies, passwords are exclusively used.

We use passwords so much that we even have rules about how to create them. This is supposed to make them less vulnerable to brute force attacks or even wild guessing. Of course, some people still use weak passwords, as evidenced in a recent report from NordPass. It's hard to believe that in 2020 people are still using 12345 as well as a bunch of other guessable words like chocolate, password and God to protect their most sensitive assets.

There will always be those who don't care to use strong passwords, but most professional organizations will force users to craft their access words or phrases in certain ways. We all know the rules by now with passwords needing to be at least eight characters and comprised of both capital and lower case letters with at least one number and a special character required.

The bad thing is that even if users adhere to the rules for making the strongest kinds of passwords, it may not do any good if they are all stored in plaintext. The password 12345 is just as bad as Nuts53!SpiKe&Dog12 if a hacker is able to read the entire password file.

Why is storing passwords in plaintext dangerous?

Storing passwords in plaintext is bad because it puts both the system and users at risk. Obviously, having a hacker able to find and read every single password used to access a system would be a disaster. They could simply find a user with administrator credentials and compromise the entire system or site. And because they would be utilizing proper user names and passwords, internal security may not catch the intrusion or catch it long after the damage is done.

Making it easy for attackers to steal passwords stored in plaintext also hurts users, because many people reuse passwords. Because we have made passwords so difficult to create, a lot of people resort to reusing ones that they can remember on multiple sites. If an attacker compromises a password file, they will almost certainly try to access other systems using the same name and password, which puts users at great risk of secondary crimes.

It's relatively easy to accidentally store passwords in plain text or not realize that this could cause major problems down the road. For example, the following code is a common method employed to store passwords when defining an AWS resource using Terraform templates:

resource "aws_db_instance" "default" {
 engine                 = "mysql"
 allocated_storage      = 10
 instance_class         = "db.t2.micro"
 username               = "admin"
 password               = "s3.cr3t.admin.p2ss"
 db_subnet_group_name   = aws_db_subnet_group.default.name
 vpc_security_group_ids = [aws_security_group.default.id]
}

In that example, the password used to manage the MySQL database instance in AWS is being stored in plaintext. That means that anyone with access to the source code repository could read, or even copy it.

Protecting passwords varies depending on the framework, but protection methods exist for every platform. For example, MySQL password can be stored in a  secure storage like AWS Secrets Manager:

resource "aws_db_instance" "default" {
 engine            = "mysql"
 allocated_storage = 10
 instance_class    = "db.t2.micro"
 username          = "admin"
 password = "${data.aws_secretsmanager_secret_version.password.secret_string}"
 db_subnet_group_name   = aws_db_subnet_group.default.name
 vpc_security_group_ids = [aws_security_group.default.id]
}

In that example, the Terraform template will get the password from AWS Secrets Manager service and it will never be stored in plaintext in template files.

Protecting passwords by avoiding plaintext storage

Passwords are the keys to your kingdom and should never be stored in plaintext. Even those internal to an organization shouldn't have access to a big, unprotected repository of passwords, nor should this be an accepted business protocol (there are plenty of password managers that allow encrypted credential sharing these days - no excuses!). There is also the danger of malicious insiders snooping files and gaining access where they shouldn't.

And with an outside attack, just imagine the double-whammy that is possible if a back door to your database is found through something as simple as a SQL injection vulnerability, and they gain access to the directory where the passwords are stored as well. Think this is too many error-laden steps to come to fruition? Sadly, this exact scenario happened in Sony's 2011 breach. Over one million customer passwords were stored in plaintext, and the Lulzsec hacking group accessed those and much more through a common SQL injection attack.

All passwords should be protected by whatever defenses are available within the supporting framework. For Terraform, passwords should never be stored in template files. It is recommended to use secure storage like AWS Secrets Manager or Azure Key Vault, depending on the infrastructure provider.

Forcing users to create secure passwords is a good idea, but then you need to do your part on the backend as well. Keeping passwords out of plaintext storage will go a long way to protecting your users and your systems. The main danger of plaintext password storage is the poor access control; essentially, anyone can see them. It's imperative (especially in an IaC environment where suddenly, more people have access to sensitive information) that they are adequately hashed and only those who absolutely require access are granted it.

Check out the Secure Code Warrior blog pages for more insight about this vulnerability and how to protect your organization and your customers from the ravages of other security flaws and vulnerabilities. You can also try a demo IaC challenge within the Secure Code Warrior training platform to keep all your cybersecurity skills honed and up to date.


Table of contents

Download PDF
View Resource
Interested in more?

Matias Madou, Ph.D. is a security expert, researcher, and CTO and co-founder of Secure Code Warrior. Matias obtained his Ph.D. in Application Security from Ghent University, focusing on static analysis solutions. He later joined Fortify in the US, where he realized that it was insufficient to solely detect code problems without aiding developers in writing secure code. This inspired him to develop products that assist developers, alleviate the burden of security, and exceed customers' expectations. When he is not at his desk as part of Team Awesome, he enjoys being on stage presenting at conferences including RSA Conference, BlackHat and DefCon.

Secure Code Warrior is here for your organization to help you secure code across the entire software development lifecycle and create a culture in which cybersecurity is top of mind. Whether you’re an AppSec Manager, Developer, CISO, or anyone involved in security, we can help your organization reduce risks associated with insecure code.

Book a demoDownload
Share on:
Resource hub

Resources to get you started

More posts
Resource hub

Resources to get you started

More posts