Using AWS CodeArtifact with AWS CodeBuild: An Angular Build Example

Using AWS CodeArtifact with CodeBuild: An Angular Build Example

AWS CodeArtifact enables you to store your custom packages or fetch packages from public package registries and use them in your software development process. If you use AWS CodeBuild to build your code, you can make CodeBuild retrieve the packages required for your build or test commands from your CodeArtifact repository on AWS instead of public Internet registries.

In this post, I will introduce you to AWS CodeArtifact and provide an example of using it with AWS CodeBuild to build an Angular application.

What is AWS CodeArtifact?

AWS CodeArtifact is a serverless package management service provided by AWS. It helps you store, publish, and share software packages using popular package management tools like npm, pip, Maven, RubyGems, etc. You can store your custom packages or packages from language-native public registries in your CodeArtifact repositories.

Why use AWS CodeArtifact?

If you need a central package management solution, maintaining and scaling your own system is costly, time-consuming, and challenging. Instead, you can use AWS CodeArtifact to let AWS manage it for you.

  • AWS CodeArtifact is serverless. It is hosted on Amazon S3 and DynamoDB tables. Not only does CodeArtifact free you from the server management burden, but it also redundantly stores your repository data in multiple AZs and automatically scales your repositories based on demand theoretically without limits. Hence, AWS CodeArtifact provides durability and high availability out of the box.

  • It is cost-effective. You only pay for the storage used, the number of requests made, and data transferred out of an AWS region. Besides, the AWS free tier provides 2GB of storage and 100,000 requests per month for free.

  • It is secure. The data is encrypted at rest with KMS keys, which can be customer-managed or AWS-managed. The data in transit is encrypted with TLS encryption. You use IAM roles and resource policies on your CodeArtifact repositories to control who can access them.

  • It is integrated with CloudTrail, so you can log who accessed and when for each action taken on your CodeArtifact repositories.

  • You can create a single CodeArtifact domain within your AWS organization and share it with multiple AWS accounts as a central location for your packages.

Then, what are CodeArtifact domains and repositories? So, let’s continue with AWS CodeArtifact’s primary concepts.

AWS CodeArtifact – Primary concepts

Asset

The individual files representing packages are called assets in CodeArtifact. It is what you download and store when you fetch a package from a package management service. For example, ‘package.tgz’ files in npm packages are CodeArtifact assets.

Package

A package represents a bundle of software with its dependencies. When you install a package, you actually install a package version, which consists of a version number, such as ‘1.5.2’, a metadata and a set of assets.

Repository

A CodeArtifact repository is the primary place to store and fetch packages on CodeArtifact. It is a set of package versions from the same or different package registries. For example, you can install packages from npm or PyPi in the same CodeArtifact repository.

If a repository has packages accessed from a second repository, it becomes an upstream repository. For example, if your CodeArtifact repository has package versions from npm, CodeArtifact creates a special repository to download packages from npm. This npm repository becomes an upstream repository, and your repository becomes a downstream.

Domain

Finally, domains are top-level CodeArtifact constructs that group and manage multiple repositories. You define external and internal repositories in CodeArtifact domains and access them through your domains.

Domains also allow you to use organization policies to share your repositories between your AWS accounts. For example, you can create a CodeArtifact domain for your production environment in an AWS account in your AWS organization and use it as the central domain for your software packages in other AWS accounts. So your teams can access them easily.

All package versions are stored in CodeArtifact domains. For example, if two repositories in your domain reference the same package version, only one copy of the package asset is stored in the domain. It doesn’t matter how many repositories reference it. This avoids unnecessary duplicates in your domain.

What is AWS CodeBuild?

AWS CodeBuild is a fully managed and serverless continuous integration service. With CodeBuild, you can build and test your code from your source Git repository hosted on GitHub, GitHub Enterprise, Bitbucket, GitLab, or GitLab self-managed. It also supports AWS CodeCommit, but AWS deprecated it in July 2024.

I won’t dive into the details of AWS CodeBuild in this post. If you want to learn AWS CodeBuild, you’re welcome to join my AWS CodePipeline Step by Step course. Now, let’s continue with using AWS CodeArtifact with AWS CodeBuild.

How do you use AWS CodeArtifact repositories in a CodeBuild project?

There are a few common steps for using AWS CodeArtifact:

1) You create a CodeAritfact domain and a repository.

2) You assign necessary IAM permissions to the IAM identity, which will store packages to or download packages from your CodeArtifact repository.

3) You log in to your CodeArtifact repository using AWS CLI. The documentation refers to it as CodeArtifact CLI, but you install it with AWS CLI, and its usage is similar to that of other commands. So, I will refer to it as AWS CLI.

4) You publish your package or install a package using language-native tools such as npm publish or npm install, respectively.

Step 1 - Preparing your CodeArifact domain and repository

To begin with, you create a CodeArtifact domain that will host all your CodeArtifact repositories and package versions.

In the example below, I create a CodeArtifact domain named my-demo-domain.

Creating a CodeArtifact domain

Then, you create a new repository in your CodeArtifact domain and choose its upstream repositories from the popular central package registries.

Your repository must be created in a CodeArtifact domain. If you don’t yet have a domain, you can create it while creating your repository on the CodeArtifact Console. However, you can create a repository in an existing domain by clicking the ‘Create repository’ button, as shown below.

Creating a CodeArtifact repository in a domain

In the example below, I create a repository named my-demo-repository in the my-demo-domain created before. Although our sample project only needs npm-store (JavaScript) to install the required Node packages, I also added PyPi (Python), RubyGems (Ruby), and Maven Central Repository (Java) registries as upstream repositories to my repository as an example.

AWS CodeArtifact repository creation with upstream repos

These are repositories with external connections, and CodeArtifact uses them to store package versions from the Internet. Because they are defined as upstream for your repository, it can also access their packages. However, you can store your own packages in your repository directly.

On the review page, CodeArtifact shows the upstream and downstream repositories with a nice diagram.

Upstream and downstream repositories on AWS CodeArtifact

In this diagram, the maven-central-store, rubygems-store, npm-store, and pypi-store repositories were added as upstream repositories. my-demo-repository is a downstream repository that automatically has access to the package versions in them.

After the creation, your CodeArtifact domain will have five repositories as below.

An AWS CodeArtifact domain after the repository creation

At the beginning, your CodeArtifact repository doesn’t have any packages.

Empty CodeArtifact repository

Angular applications use Node packages. So, during the build, we expect CodeBuild to fetch some Node packages from npm and store them in the npm-store repository. However, the npm-store repository on CodeArtifact is empty beforehand.

Empty CodeArtifact upstream npm-store repository

So, let’s see what happens after integrating it with AWS CodeBuild running a build.

Step 2 – Creating your CodeBuild project

This part is almost the same as using AWS CodeBuild without CodeArtifact. Your CodeBuild project’s source can be any of the source repositories supported. It can also be a part of a CodePipeline build action, which you can learn in my AWS CodePipeline Step by Step course on Udemy.

In the example for this blog post, I use a buildspec file to build an Angular application. I won’t embed the CodeArtifact domain and repository names or AWS account ID in the buildspec file. Instead, I recommend using environment variables. So, in the example below, I create these environment variables in my CodeBuild project:

  • CODEARTIFACT_DOMAIN: The name of your CodeArtifact domain. In my example, it is ‘my-demo-domain’.

  • CODEARTIFACT_REPO: The name of your CodeArtifact repository, which is ‘my-demo-repository’ in my example.

  • CODEARTIFACT_OWNER: The AWS account ID of the owner of the repository. It will be my account ID, but it can also be from a different AWS account whose repository is configured for cross-account access.

The environment variables on CodeBuild look like the image below. You can learn to use environment variables in CodeBuild from my previous post about the subject.

CodeBuild environment variables for CodeArtifact

Step 3 – Granting your CodeBuild project necessary permissions

Your CodeBuild project won’t have permission to access CodeArtifact after the creation. So, you should provide permission to log in to CodeArtifact and access your CodeArtifact domain and repositories in its IAM service role.

You can create a customer-managed IAM policy with the permissions below.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "codeartifact:GetAuthorizationToken",
                "codeartifact:GetRepositoryEndpoint",
                "codeartifact:ReadFromRepository"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "sts:GetServiceBearerToken",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "sts:AWSServiceName": "codeartifact.amazonaws.com"
                }
            }
        }
    ]
}

Then, you should assign it to your CodeBuild project’s IAM role.

Step 4 – Adding CodeArtifact login command to your buildspec file

In CodeBuild, you provide the commands to build or test your code in your buildspecs. A buildspec consists of these optional phases in the order they are executed: install, pre_build, build, and post_build.

Usually, the pre_build phase is where you log in to central repositories, such as DockerHub or Amazon ECR. However, in the install phase before pre_build, you may also install global packages in your CodeBuild environment, such as Angular CLI. So, the place of your CodeArtifact login command depends on your buildspec file’s structure.

In my sample buildspec below, I install Angular CLI in the install phase and the project dependencies in the pre_build phase. Then, I build the Angular project in the build phase.

version: 0.2
phases:
  install:
    runtime-versions:
      nodejs: 20
    commands:
      # Install the Angular CLI
      - npm install -g @angular/cli@17

  pre_build:
    commands:
      # Install the project dependencies
      - npm install

  build:
    commands:
      # Build the Angular application
      - ng build -c production

artifacts:
  base-directory: dist/my-angular-project
  files:
    - '**/*'

If I place the CodeArtifact in the pre_build phase, the npm install command for Angular CLI in the install phase will still fetch the package from the central npm registry. But I also want CodeBuild to fetch it from CodeArtifact. So, either I would move the Angular CLI installation to the pre_build phase or place the CodeArtifact login before it.

I chose the second option. You can see the final buildspec file below.

version: 0.2
phases:
  install:
    runtime-versions:
      nodejs: 20
    commands:
      # Log in to CodeArtifact
      - echo 'Logging in to CodeArtifact...'
      - aws codeartifact login --tool npm --repository ${CODEARTIFACT_REPO} --domain ${CODEARTIFACT_DOMAIN} --domain-owner ${CODEARTIFACT_OWNER}

      # Install the Angular CLI
      - npm install -g @angular/cli@17

  pre_build:
    commands:
      # Install the project dependencies
      - npm install

  build:
    commands:
      # Build the Angular application
      - ng build -c production

artifacts:
  base-directory: dist/my-angular-project
  files:
    - '**/*'

Because the build execution logs in to CodeArtifact before all npm install commands, all required Node packages will be stored in the CodeArtifact domain first. Then, they will be installed from CodeArtifact into the CodeBuild environment.

If you joined my AWS CodePipeline Step by Step course, you are already familiar with the ‘aws ecr get-login’ command. The ‘codeartifact login’ command works similarly. It returns an authentication token to be used by the Node package manager (npm) in the HTTP Authorization header while logging in to CodeArtifact.

The Result of the Build

After executing the build project, you will have these in your logs and CodeArtifact repositories.

The CodeBuild logs

After running the build, you will see a build log for the successful login similar to the one below. Please note the build log after the CodeArtifact login command.

CodeArtifact login in the CodeBuild build logs

The authorization token returned by the ‘codeartifact login’ command provided 12 hours of access, which was much more than needed for my CodeBuild project execution.

The CodeArtifact repositories after the build

After the build, you will see your CodeArtifact repository with new package versions.

The AWS CodeArtifact repository after the build with AWS CodeBuild

Actually, these are from the upstream npm-store repository in your CodeArtifact domain.

npm-store repository on AWS CodeArtifact after the build with AWS CodeBuild

CodeArtifact automatically fetches all dependencies from your package.json file in your Node or Angular project. But if your project continues to use the same package versions, CodeArtifact will not fetch those unless you delete them. If your project references a new version, CodeArtifact will fetch it in the subsequent build execution.

Would you like to learn to use AWS CodeBuild with AWS CodePipeline?

If you want to learn to use AWS CodeBuild in your CI/CD pipelines, my AWS CodePipeline Step by Step course on Udemy may be helpful.

In this course, you will learn to use AWS CodePipeline to build CI/CD pipelines on AWS step by step to build your applications with CodeBuild and deploy them to S3 or EC2. You will also learn to create Docker images with CodeBuild and deploy Docker containers from them to Amazon ECS with CodePipeline. We cover many CodeBuild features in detail in my Udemy bestseller course.

The links in this post also provides a special discount for you. You can view all my courses on our Courses page.

Conclusion

AWS CodeArtifact provides a feasible and efficient central package management solution for your software development processes. In this post, I provided an example of using AWS CodeArtifact with your CodeBuild projects.

If you found it helpful, please also share it on your LinkedIn profile or X (Twitter) account to help me reach others like you.

Follow me on LinkedIn and X (Twitter) to hear about my future online courses or blog posts.

Thanks for reading!

References

Using AWS CodeArtifact with CodeBuild: An Angular Build Example
Emre Yilmaz

AWS Consultant • Instructor • Founder @ Shikisoft

Follow