Next Article in Journal
A Novel Framework Leveraging Large Language Models to Enhance Cold-Start Advertising Systems
Previous Article in Journal
Enhancing Industrial Processes Through Augmented Reality: A Scoping Review
 
 
Font Type:
Arial Georgia Verdana
Font Size:
Aa Aa Aa
Line Spacing:
Column Width:
Background:
Article

Creating Automated Microsoft Bicep Application Infrastructure from GitHub in the Azure Cloud

Department of Computer Systems, Faculty of Computer Systems and Technologies, Technical University of Sofia, 1000 Sofia, Bulgaria
*
Author to whom correspondence should be addressed.
Future Internet 2025, 17(8), 359; https://doi.org/10.3390/fi17080359 (registering DOI)
Submission received: 16 July 2025 / Revised: 2 August 2025 / Accepted: 5 August 2025 / Published: 7 August 2025
(This article belongs to the Special Issue IoT, Edge, and Cloud Computing in Smart Cities, 2nd Edition)

Abstract

Infrastructure as code (IaC) is essential for modern cloud development, enabling teams to define, deploy, and manage infrastructure in a consistent and repeatable manner. As organizations migrate to Azure, selecting the right approach is crucial for managing complexity, minimizing errors, and supporting DevOps practices. This paper examines the use of Azure Bicep with GitHub Actions to automate infrastructure deployment for an application in the Azure cloud. It explains how Bicep improves readability, modularity, and integration compared to traditional ARM templates and other automation tools. The solution utilizes a modular Bicep design to deploy resources, including virtual networks, managed identities, container apps, databases, and AI services, with environment-specific parameters for development, QA, and production. GitHub Actions workflows automate the building, deployment, and tearing down of infrastructure, ensuring consistent deployments across environments. Security considerations include managed identities, private networking, and secret management in continuous integration (CI) and continuous delivery (CD) pipelines. This paper provides a detailed architectural overview, workflow analysis, and implementation guidance to help teams adopt a robust, automated approach to Azure infrastructure deployment. By leveraging automation tooling and modern DevOps practices, organizations can streamline delivery and maintain secure, maintainable cloud environments.

1. Introduction

Cloud computing has transformed how organizations design, deploy, and operate software systems. By providing on-demand, scalable resources and managed services, cloud platforms like Microsoft Azure enable teams to accelerate delivery cycles, reduce infrastructure costs, and focus on delivering business value. As cloud adoption has grown, so too has the complexity of managing cloud resources consistently and securely across multiple environments.
The approach has been chosen because it enables a highly flexible and efficient deployment model that aligns with the evolving needs of modern software engineering teams. In many development and testing contexts, there is a clear requirement to provision complete environments—including networking components, databases, containerized applications, and supporting services—in a matter of minutes with minimal manual intervention. By adopting a declarative, code-driven infrastructure definition combined with automated CI/CD workflows, this approach allows teams to reliably and predictably deploy infrastructure on demand. Equally important, it supports the rapid and secure decommissioning of resources when they are no longer required, helping to control cloud costs and reduce operational complexity. This ephemeral infrastructure model adheres to best practices for treating infrastructure as disposable and reproducible, facilitating experimentation while ensuring consistent configurations across environments. The integration of Azure Bicep with GitHub Actions was specifically selected to deliver this level of flexibility while maintaining strong security controls, role-based access management, and environment-specific parameterization across development, QA, and production stages [1,2].
Traditionally, infrastructure provisioning was a manual and error-prone process. Engineers would create resources via web portals or CLI commands, often with limited standardization or documentation. This approach resulted in slow, inconsistent, and difficult-to-reproduce deployments. Manual configuration increased the risk of security vulnerabilities and misconfigurations, while making it challenging to maintain parity between development, testing, and production environments. As organizations adopted DevOps practices to shorten release cycles and enhance software quality, the need for automation and repeatability in infrastructure management became increasingly clear.
Infrastructure as code has emerged as a core DevOps practice through which to address these challenges. The programmable infrastructure enables teams to define cloud infrastructure declaratively using code files that can be version-controlled, reviewed, and tested like application code. By codifying infrastructure, teams can ensure consistent deployments, simplify rollback and disaster recovery processes, and facilitate collaboration across development and operations. Popular tools include AWS CloudFormation, HashiCorp Terraform, and Azure’s ARM templates. Each tool has trade-offs in terms of complexity, ease of use, and integration with specific cloud providers.
Within the Azure ecosystem, Bicep has become a modern alternative to traditional ARM JSON templates. Bicep is a domain-specific language (DSL) for declarative provisioning of Azure resources. It improves on ARM templates by providing a more concise, readable, and modular syntax while maintaining full compatibility with the Azure Resource Manager. Bicep enables teams to split complex deployments into reusable modules, parameterize environments, and support infrastructure definitions as first-class code artifacts. By reducing boilerplate and improving maintainability, Bicep lowers the barrier to adopting automated infrastructure provisioning on Azure [2,3,4].
At the same time, continuous integration and continuous delivery (CI/CD) have become essential for modern software development. CI/CD practices automate the build, test, and deployment stages of application delivery, ensuring that changes are integrated frequently, thoroughly tested, and reliably deployed. GitHub Actions is a popular CI/CD platform that integrates seamlessly with GitHub repositories, offering flexible workflows, secure secret management, and strong community support. By combining GitHub Actions with Azure Bicep, teams can fully automate the deployment of cloud infrastructure and application code from source control, achieving consistent and secure deployments across multiple environments.
This paper addresses the design and implementation of an automated deployment pipeline for an application hosted in the Azure cloud. The solution utilizes Azure Bicep to define the required infrastructure and GitHub Actions to automate the deployment process. The targeted infrastructure includes a virtual network with private subnets, an Azure Container App hosting the application, Azure Database for PostgreSQL with delegated networking, Azure Cognitive Search, Managed Identities for secure access control, and supporting resources such as Private DNS Zones. The design emphasizes security best practices, such as using private endpoints to restrict access to Azure services and managing secrets via GitHub repository secrets [5].
A key goal of this solution is to support multiple deployment environments—Development, QA, and Production—with a single codebase and parameterized configurations. By adopting a modular Bicep approach, the infrastructure is split into smaller, reusable components that can be composed flexibly. Parameter files enable environment-specific customization, such as different networking configurations, database credentials, or service capacities. This approach aligns with industry best practices for multi-environment deployments, ensuring consistent architecture while allowing environment-specific tuning.
To orchestrate deployments, the solution includes GitHub Actions workflows for both deployment and infrastructure teardown. The deployment workflow supports selective targeting of Azure Container Registry (ACR) resources, the infrastructure resources defined in Bicep, or both. It ensures that required resource groups are created if missing, builds and pushes Docker images for the application, and deploys the Bicep-defined infrastructure with the correct parameters. The teardown workflow provides a safe, automated way to delete resource groups and clean up associated role assignments and resources. This level of automation reduces manual effort, minimizes human error, and improves the consistency and auditability of deployments.
Beyond the technical implementation, this paper examines the choice of Azure Bicep in relation to other automation tools, considering factors such as the learning curve, cloud-native integration, and support for Azure-specific features. It also examines the benefits of utilizing GitHub Actions over other CI/CD solutions, including ease of use, pricing, and seamless integration with GitHub repositories.
The objectives of this paper are threefold. First, it aims to demonstrate the design of a secure, modular, and automated infrastructure deployment pipeline for Azure using Bicep and GitHub Actions. Second, it seeks to provide practical guidance and real-world examples to help practitioners adopt similar approaches in their own projects. Third, it evaluates the strengths and limitations of the chosen tools to inform decision making around programmable infrastructure and CI/CD strategies for Azure-based development.
By combining Azure-native software-defined infrastructure with modern CI/CD automation, this approach provides a robust, maintainable, and scalable framework for securely and consistently deploying applications to Azure.

2. Background and Related Work

2.1. Infrastructure as Code Concepts

Infrastructure as code is a fundamental practice in modern cloud engineering that enables teams to define and provision infrastructure through machine-readable definition files, rather than performing manual configurations. By treating automated infrastructure provisioning, organizations can achieve consistent, repeatable, and auditable deployments across different environments. This approach is central to DevOps methodologies, where automation, collaboration, and rapid iteration are essential for delivering software reliably and at scale. IaC has emerged as a core DevOps practice through which to address these challenges. In its early stages, infrastructure provisioning was a manual, time-consuming task heavily reliant on system administrators configuring servers and networks by hand. This process was not only error-prone but also challenging to document and reproduce. Over time, the industry began shifting toward automation with the introduction of scripting and configuration management tools. These solutions allow teams to version-control infrastructure code, manage it as part of the application lifecycle, and fully integrate with CI/CD pipelines, thus significantly improving reliability, security, and scalability.
Automation tools generally fall into two paradigms: declarative and imperative. In a declarative approach, the desired end state of the infrastructure is described without specifying the exact sequence of steps needed to achieve it. Tools such as Azure Bicep, Terraform, and AWS CloudFormation enable users to define the resources they want and their properties. At the same time, the underlying deployment engine determines how to reconcile the current state with the target state. Declarative is particularly valued for its idempotency, ensuring that applying the same configuration multiple times yields the same result each time [4,5].
By contrast, imperative software-defined infrastructure specifies the exact commands or steps required to provision resources. While this approach offers fine-grained control, it can lead to more brittle, complex, and error-prone deployments, especially at scale. Scripting tools like Ansible (in specific modes) or custom shell scripts exemplify this approach. In practice, the declarative model has become the preferred strategy for defining cloud infrastructure, as it simplifies management and reduces human error.
The benefits of adopting IaC in a DevOps context are substantial. The programmable infrastructure promotes consistency and repeatability, ensuring that resources are provisioned in the same way across development, QA, and production environments. It enables version control of infrastructure definitions, facilitating code reviews, change tracking, and rollback in case of issues. Collaboration between developers and operations teams improves when infrastructure is represented as code, reducing silos and miscommunication. Automation through CI/CD pipelines further enhances reliability by eliminating manual steps and integrating infrastructure deployment into the overall delivery process. Finally, automated infrastructure provisioning improves compliance and security by providing a clear, auditable trail of changes and configurations, making it easier to enforce policies and detect drift over time [6,7,8].

2.2. Azure Bicep Overview

Within the Azure ecosystem, Bicep represents a modern approach to declaratively defining cloud infrastructure. Introduced by Microsoft as an evolution of Azure Resource Manager (ARM) templates, Bicep addresses many of the pain points associated with traditional ARM JSON files. While ARM templates are powerful and widely used, they are often criticized for their verbosity, complexity, and poor readability, especially in large-scale deployments.
Azure Bicep is a domain-specific language (DSL) explicitly designed to simplify Azure resource provisioning. It compiles transparently to ARM JSON templates, meaning all existing Azure features are supported without sacrificing compatibility. Unlike JSON, Bicep offers a more concise and human-friendly syntax that reduces boilerplate and improves maintainability. This makes it easier for teams to adopt infrastructure as code practices without requiring extensive training or wrestling with cumbersome syntax [7,9].
One of the key advantages of Bicep over ARM templates is its support for modularity. With Bicep, teams can define reusable modules for different infrastructure components, promoting code reuse and more precise separation of concerns. Parameters and variables are more intuitive, while tools such as Visual Studio Code extensions provide rich IntelliSense, type checking, and validation features that reduce errors during authoring.
For example, defining a storage account in ARM JSON requires numerous nested properties and brackets, meaning it can quickly become unwieldy, even for simple resources. In Bicep, the exact definition is reduced to a clear, concise block with improved readability. This clarity is crucial for teams managing large infrastructures or multiple environments, where maintainability and ease of understanding are critical [9,10].
ARM JSON:
{
  “$schema”: “https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#”,
  “contentVersion”: “1.0.0.0”,
  “resources”: [
    {
       “type”: “Microsoft.Storage/storageAccounts”,
       “apiVersion”: “2022-09-01”,
       “name”: “[parameters(‘storageAccountName’)]”,
       “location”: “[resourceGroup().location]”,
      “sku”: {
         “name”: “Standard_LRS”
       },
       “kind”: “StorageV2”,
       “properties”: {}
     }
  ],
  “parameters”: {
    “storageAccountName”: {
      “type": “string"
    }
  }
}
BICEP:
param storageAccountName string

resource storageAccount ‘Microsoft.Storage/storageAccounts@2022-09-01’ = {
  name: storageAccountName
  location: resourceGroup().location
  sku: {
    name: ‘Standard_LRS’
  }
  kind: ‘StorageV2’
}
Importantly, Bicep retains full compatibility with Azure’s deployment engine. Bicep files compile to ARM templates, meaning all existing deployment mechanisms, policies, and tooling continue to work seamlessly. This ensures that teams adopting Bicep can do so incrementally, without risking compatibility with existing workflows. Bicep represents a significant improvement in authoring experience for Azure infrastructure as code. By emphasizing readability, modularity, and native Azure integration, it lowers the barrier to adopting automated infrastructure provisioning while enabling sophisticated, production-grade deployments [11,12,13].

2.3. Comparison with Alternative Tools

While Bicep offers compelling advantages for Azure-focused teams, it is not the only programmable infrastructure solution available. Many organizations evaluate tools such as Terraform, Pulumi, and AWS CloudFormation, each of which brings its strengths and trade-offs.
Terraform, developed by HashiCorp, is one of the most popular infrastructure as code tools in the industry. It utilizes the declarative HashiCorp Configuration Language (HCL) to define infrastructure and supports a wide array of cloud providers and services through its extensive provider ecosystem. Terraform’s key strength lies in its multi-cloud capability, enabling organizations to use a single tool and language to manage resources across Azure, AWS, GCP, and many other cloud platforms. It also offers state management, which tracks deployed resources and enables sophisticated operations such as drift detection and incremental updates. Terraform’s Azure provider can sometimes lag new Azure features, and managing state files introduces operational complexities such as secure storage and team coordination.
Pulumi takes a different approach by enabling infrastructure definitions in general-purpose programming languages such as TypeScript, Python, Go, and .NET. This enables developers to utilize familiar language features, abstractions, and packages to model infrastructure, offering unparalleled flexibility and ease of use. Pulumi is well suited to teams that want to integrate complex business logic into infrastructure provisioning or build highly reusable infrastructure components. This power comes with trade-offs, including a steeper learning curve for operations teams, a requirement for runtime environments during execution, and reliance on cloud provider support for achieving full feature parity [12,14,15].
AWS CloudFormation is Amazon’s native declarative Infrastructure as Code service, using JSON or YAML to define AWS resources. It offers deep integration with AWS services, supporting advanced features like change sets, drift detection, and nested stacks. CloudFormation is the gold standard for AWS-centric deployments but is inherently AWS-specific. Its verbosity and complexity can also be challenging in large-scale implementations, such as ARM templates, before the introduction of Bicep.
When comparing Bicep with these alternatives, several themes emerge. Bicep’s Azure-native design ensures the fastest adoption of new Azure features and the most seamless integration with Azure Resource Manager. Its syntax and modularity make it highly accessible, even to teams with limited experience in software-defined infrastructure. Bicep is Azure-only and does not support multi-cloud use cases, which may be a limitation for organizations with hybrid or multi-cloud strategies. In contrast, Terraform and Pulumi offer cross-cloud flexibility at the cost of greater complexity and potential feature gaps for the latest Azure services. Ultimately, the choice of a programmable infrastructure tool depends on an organization’s priorities, skill sets, and deployment targets, as shown in Table 1. This table summarizes the main features, strengths, and limitations of Azure Bicep, Terraform, Pulumi, and AWS CloudFormation. It provides a side-by-side comparison in terms of language type, cloud provider support, integration, ease of use, modularity, state management, learning curve, and ideal usage scenarios, helping teams select the appropriate tool for their DevOps and automation needs.

2.4. Role of GitHub Actions in CI/CD

While infrastructure as code enables consistent and reliable definition of cloud resources, achieving true automation and repeatability requires integration with robust continuous integration and continuous delivery (CI/CD) systems. The pipelines automate the process of building, testing, and deploying application code and infrastructure, reducing manual effort and human error while accelerating delivery cycles.
GitHub Actions is GitHub’s integrated CI/CD platform, providing an event-driven automation framework directly within GitHub repositories. It allows developers to define workflows using YAML files that respond to events such as code pushes, pull requests, or scheduled triggers. By leveraging GitHub Actions, teams can automate the entire deployment pipeline from building Docker images to deploying infrastructure with Bicep templates.
One of the key advantages of GitHub Actions is its tight integration with GitHub itself. Repository events, branch protections, pull request checks, and status reporting are all natively supported, making it an intuitive choice for teams already using GitHub for source control. Additionally, GitHub Actions supports secure secret management, enabling safe handling of service principal credentials or other sensitive information required for Azure deployments [15].
Compared with Azure DevOps, another Microsoft offering, GitHub Actions is generally simpler and more lightweight, favoring ease of use and Git-native workflows. Azure DevOps offers a comprehensive suite of features, including work item tracking, test plans, artifacts, and advanced pipeline configurations, making it well suited for large enterprises with more complex governance requirements. For many teams, GitHub Actions offers sufficient capabilities without the overhead of managing separate tools.
Jenkins, a mature, self-hosted automation server, has long been a staple of the CI/CD landscape. It is renowned for its flexibility and massive plugin ecosystem, supporting virtually any build and deployment scenario. Jenkins requires teams to manage their own infrastructure, updates, and security configurations, which can become burdensome over time. In contrast, GitHub Actions is fully managed, reducing operational effort while offering built-in security features.
GitLab CI is another integrated CI/CD solution, like GitHub Actions, that is closely tied to its respective source control platform. It offers strong features, including free runners, pipelines as code, and a user-friendly interface. While GitLab CI is well suited for teams on GitLab, GitHub Actions provides better integration with Azure through official deployment actions and a broader marketplace of community-contributed actions.
In summary, GitHub Actions plays a critical role in enabling secure, automated, and repeatable infrastructure deployments. By integrating closely with Azure and Bicep, it simplifies the process of delivering cloud applications in a consistent, scalable, and maintainable manner. This tight coupling of programmable infrastructure and CI/CD practices forms the foundation for modern DevOps workflows in the Azure ecosystem [16].

3. Project Overview and Objectives

3.1. Purpose of the Project

The purpose of this project is to design, implement, and document an automated cloud infrastructure deployment pipeline for an application using Azure Bicep and GitHub Actions. The project aims to demonstrate how automated infrastructure provisioning practices can be utilized to provision and manage Azure resources in a consistent, repeatable, and secure manner. By leveraging Azure Bicep—a modern, declarative IaC language designed for Azure and integrating it with GitHub Actions for Continuous Integration and Continuous Deployment—the project aims to create a robust automation workflow that development teams of varying sizes can adopt. The full repository structure is presented in Figure 1.
At its core, the project seeks to bridge the gap between application development and infrastructure management by embedding infrastructure provisioning directly into the software delivery lifecycle. Rather than relying on manual configurations or ad hoc scripts, the proposed solution presents a clean and maintainable approach that aligns with modern DevOps practices. The use of Azure Bicep ensures that infrastructure definitions are not only machine-readable but also human-friendly, promoting collaboration between development and operations teams.
This approach is designed to serve as a blueprint for organizations adopting Azure as their primary cloud provider, particularly those developing microservices or web applications. By demonstrating a real-world deployment pipeline, the project provides tangible guidance on integrating automated infrastructure provisioning into day-to-day development workflows, reducing friction, and accelerating time to market [17,18].

3.2. Business and Technical Problem Statement

Modern software projects face significant challenges in managing cloud infrastructure at scale. Manual provisioning of resources introduces the risk of human error, environmental drift, and inconsistent configurations across development, testing, and production environments. Without automation, deploying infrastructure changes becomes time-consuming, error-prone, and difficult to audit. These challenges are further amplified in teams practicing agile development, where frequent iteration demands infrastructure that is as adaptable and reliable as the application code itself.
The technical problem addressed by this project is the lack of a standardized, automated, and secure mechanism to deploy the necessary Azure infrastructure for an application. In many organizations, infrastructure definitions are scattered across documents or scripts that lack version control, making them hard to maintain and impossible to reuse. When multiple teams or developers work on the same system, this fragmentation leads to misconfigurations, deployment delays, and increased costs due to resource sprawl or incorrect sizing.
From a business perspective, these technical issues result in higher operational costs, longer delivery cycles, and an increased risk of service outages. Regulatory requirements may further demand auditable, repeatable deployment processes that many organizations cannot meet without adopting infrastructure as code. For companies aiming to scale their operations or rapidly deliver new features, these inefficiencies become critical blockers.
The project specifically seeks to solve these problems by defining the entire Azure infrastructure required for the application in Bicep modules stored in a GitHub repository. These modules will be version-controlled, reusable, and easy to audit. Deployment will be triggered automatically through GitHub Actions workflows, ensuring consistent environments for development, quality assurance, and production [19].

3.3. Goals of Automated Deployment

The primary goal of this project is to implement a complete automation pipeline that enables teams to deploy infrastructure and applications to the cloud reliably, securely, and repeatably. More specifically, the project’s goals include the following:
-
Consistency: One must ensure that every deployment of the infrastructure is identical across all environments, thereby reducing drift and manual errors. Automated deployments reduce the risk of environment-specific configurations being unintentionally introduced. Each environment—development, QA, and production—is provisioned from the same source code and templates, guaranteeing a uniform setup. This consistency simplifies testing, reduces troubleshooting time, and increases overall system reliability. In turn, this creates a more predictable foundation for application behavior and performance across stages.
-
Maintainability: Azure Bicep’s modular, human-readable syntax can be used to make infrastructure code easy to review, update, and extend. By abstracting common patterns into discrete modules, updates can be localized without disrupting other components. The declarative nature of Bicep helps teams focus on what should be provisioned rather than how, making changes intuitive even for newcomers. Code is structured to align with best practices in software engineering, such as separation of concerns and single responsibility. This approach significantly reduces technical debt and allows the infrastructure to evolve with project needs.
-
Reusability: One can build reusable Bicep modules that encapsulate best practices for defining Azure resources, such as networking, storage, and compute. These modules are designed to be parameterized and environment-agnostic, enabling broad applicability across multiple projects. For example, a single networking module can serve different applications by adjusting only a few parameters, such as CIDR ranges or subnet names. Reusability also accelerates new deployments by reducing the need to rewrite foundational code from scratch. As modules mature, they serve as standardized building blocks aligned with organizational governance.
-
Automation: Manual deployment steps can be eliminated through GitHub Actions workflows, enabling truly continuous delivery of infrastructure. This automation reduces the burden on DevOps teams and minimizes the risk of human error during critical operations. Automated validation, formatting, and linting steps are also incorporated to maintain code quality throughout the CI/CD process. The automation design supports rapid iteration while maintaining compliance with organizational standards.
-
Security: Secure credential management can be integrated using GitHub Secrets, enforcing least privilege and protecting sensitive information during deployment. Service principles used for automation are scoped only to the necessary resources and roles, in line with the principle of least privilege. Credentials are stored in encrypted GitHub secrets, which are only accessible to approved workflows and never exposed in logs or code. This prevents unauthorized access and reduces the attack surface for the deployment pipeline. Additionally, secret rotation policies can be easily implemented to reduce the long-term risk of credential compromise.
-
Traceability: Git version control can be leveraged for all infrastructure definitions, enabling teams to track changes over time, perform code reviews, and roll back when necessary. Every modification to the infrastructure codebase is captured in a committed history, making it easy to audit and reason about changes. Pull requests can be used to conduct peer reviews and apply automated tests before code is merged. In the event of a failed deployment or misconfiguration, previous known-good states can be restored with minimal effort. This provides not only technical transparency but also governance and compliance value.
-
Collaboration: Developers and operations teams are enabled to work together on a single source of truth for infrastructure, fostering shared ownership and reducing silos. The adoption of IaC empowers developers to contribute directly to infrastructure definitions without relying solely on DevOps engineers. Documentation, comments, and a clear module structure lower the barrier to entry for team members with different backgrounds. Git-based workflows further encourage collaboration by integrating infrastructure into the same review and release processes as application code. This cultural shift supports agile methodologies and enhances organizational agility.
-
Cost Control: The creation of appropriately sized environments is supported, avoiding overprovisioning and enabling easier teardown of unused resources. Automation allows teams to rapidly provision ephemeral environments for testing, which can be destroyed automatically when no longer needed. Parameters and templates include options to define SKU sizes, storage tiers, and scaling rules, helping teams correctly size their infrastructure. Cost tracking tags are also integrated to provide better visibility into resource usage across environments. Over time, this improves budgeting accuracy and aligns cloud expenditure with actual operational needs.
By achieving these goals, the project demonstrates how modern DevOps principles can be practically applied to infrastructure management in Azure, using tools that are accessible to teams with varying levels of cloud expertise. It also provides a model that can be scaled up or adapted to meet the needs of larger organizations with more complex compliance, security, or governance requirements [20].
To enhance the clarity and practical applicability of the proposed goals, and to support potential future evaluations (e.g., KPI tracking or empirical validation), we introduce a weighted prioritization scheme. Each goal is assigned a relative importance score on a scale from 1 (lowest priority) to 5 (highest priority), reflecting its impact on the reliability, security, and maintainability of automated infrastructure in cloud-native environments.
This prioritization serves multiple purposes:
-
It guides readers in understanding which aspects of the design were most critical to the authors.
-
It enables teams seeking to implement similar architectures to focus their resources strategically.
-
It lays the foundation for potential quantitative assessment of goal achievement in future extensions of the project.
Table 2 summarizes the relative weights and justifications for each goal.

3.4. Target Environments

A crucial part of this project is designing the automated deployment to support multiple target environments, specifically development (dev), quality assurance (QA), and production (prod). Each environment serves a distinct purpose in the software delivery lifecycle, and the infrastructure automation must accommodate its unique requirements while ensuring consistency and repeatability.
-
Development Environment (Dev):
The dev environment is intended for active development work, frequent testing, and rapid iteration. Infrastructure in this environment should be lightweight and cost-efficient, while still closely mirroring production configurations to ensure meaningful testing. The automated deployment should support easy creation and teardown of dev environments, enabling developers to spin up isolated sandboxes on demand.
-
Quality Assurance Environment (QA):
The QA environment serves as the staging ground for more formal testing, including integration, regression, and user acceptance testing. It must replicate production configurations as closely as possible to identify and resolve issues before deployment to end users. Automated deployment ensures that QA environments can be refreshed reliably, maintaining alignment with the latest production infrastructure definitions.
-
Production Environment (Prod):
The production environment is the live system serving real users. It requires the highest level of stability, security, and compliance. Automated deployment pipelines for production must include additional safeguards such as manual approvals, policy enforcement, and monitoring integrations. The Bicep modules and GitHub Actions workflows must support these production-specific requirements while maintaining the same core definitions as dev and QA, ensuring true environment parity.
By explicitly supporting these target environments, the project embodies a key DevOps principle: “if it works in dev, it should work in prod.” Consistent, automated deployment across environments reduces bugs caused by configuration drift, accelerates delivery cycles, and increases confidence in releases. It also supports practices such as blue-green deployments or canary releases, which rely on the ability to reproduce infrastructure consistently across multiple parallel environments [21].

4. Solution Architecture

4.1. High-Level Architecture Diagram

At the heart of this project is a carefully designed cloud architecture that leverages Azure’s Platform-as-a-Service (PaaS) and Infrastructure-as-a-Service (IaaS) components to host a web application, as shown in Figure 2. The solution architecture is designed for high availability, security, and ease of maintenance, while also supporting development, QA, and production environments through parameterization.
This architecture is designed around a secure Virtual Network (VNet) that isolates all resources, ensuring that traffic between services flows through private endpoints rather than public IP addresses. Core components include the following:
-
A Virtual Network with multiple subnets (including delegated subnets for specific services).
-
The Azure Container App to run the application in a serverless container environment.
-
A PostgreSQL Flexible Server for the relational database needs of the application, connected through private endpoints.
-
Azure AI Search to provide robust search capabilities with integrated private endpoint connectivity.
-
Managed identity for secure authentication between the app and other Azure services without embedded secrets.
-
The Azure Container Registry to store container images for deployment.
All components are provisioned and managed via Bicep templates, ensuring consistency across environments. The entire deployment is automated via GitHub Actions, enforcing infrastructure as code principles and enabling continuous delivery.

4.2. Azure Resource Provision

This section details the specific Azure resources provisioned by the Bicep templates in this project. Each resource has been carefully selected to support the application’s requirements while enforcing best practices in security, cost optimization, and maintainability [20,22].

4.2.1. Virtual Network

The Azure Virtual Network (VNet) forms the backbone of the infrastructure, providing logical isolation and secure communication between resources. Networking is a foundational module in this design. It defines the Azure Virtual Network (VNet), subnets, and delegations required for the application. By parameterizing address spaces and subnet definitions, the networking module can adapt to the IP requirements of different environments while enforcing best practices such as subnet delegation for Azure Container Apps environments. This approach ensures that services can communicate securely within private networks, avoiding exposure to public internet endpoints where not required. It includes the following:
-
Definition of address space to segment IP ranges appropriately.
-
Multiple subnets, with dedicated subnets for application containers; database services; Azure AI Search; and private endpoints.
-
Delegated subnets where needed (for Azure Container Apps), enabling Azure to manage necessary network configurations while maintaining isolation.
-
Integration with Azure Private DNS Zones for private name resolution of resources.
Bicep modules define the VNet structure declaratively, including subnet configurations and delegations. This modular approach enables easy adjustment of address ranges or subnet assignments for different environments. The full source code is provided in Appendix A.

4.2.2. Azure Container App

Azure Container Apps are used to host applications in a serverless container environment. Key design aspects include the following:
-
A container image pulled from Azure Container Registry (ACR).
-
Ingress configuration, optionally restricted to internal access only.
-
Managed Identity integration, allowing the app to authenticate securely to Azure resources (PostgreSQL, Azure AI Search) without storing secrets.
-
Scaling rules to automatically adjust capacity based on load.
The Bicep definitions encapsulate Container App environments and app configuration, ensuring consistent deployments across dev, QA, and production. The complete deployment template for the Azure Container App, which integrates secrets, managed identity, and environment variables, is provided in Appendix B.

4.2.3. PostgreSQL Flexible Server

PostgreSQL Flexible Server is a managed database solution chosen for its high availability, automated backups, and fine-grained network control. The database module provisions an Azure Database for the PostgreSQL Flexible Server, designed to support secure, scalable, and environment-specific configurations. Parameterization of administrative credentials, storage capacity, and performance SKUs ensures that development environments can utilize cost-effective resources while production systems can be scaled for high availability and performance. The module also supports VNet integration connectivity, ensuring that database traffic remains on Azure’s internal network backbone for improved security and compliance. The Bicep template provides the following:
-
Private endpoint connectivity to the VNet.
-
VNet integration for traffic isolation.
-
Tier and compute size parameters, allowing environments to use cost-optimized or production-grade configurations.
-
Admin credentials stored securely in Azure Key Vault, with deployment-time parameterization.
This approach ensures that production data remains secure while supporting lighter-weight dev/QA configurations. The complete infrastructure definition for secure PostgreSQL provisioning, including private network integration, is included in Appendix C.

4.2.4. Azure AI Search

Azure AI Search provides full-text search capabilities for the application. The AI Search module provides Azure Cognitive Search, a key service for enabling advanced text search and indexing capabilities within the application. The module supports parameterized pricing tiers to optimize cost and performance trade-offs for each environment. Moreover, integration with Private Endpoints ensures that search traffic is secured against unauthorized access and remains within Azure’s trusted network. The Bicep modules define the following:
-
Search service provisioning, including SKU and partition count parameters;
-
Private endpoint configuration to eliminate public access;
-
Integration with the Virtual Network and Private DNS Zones.
This enables the application to perform secure, performant search queries without exposing the search endpoint publicly. The complete template for securely deploying Azure Cognitive Search with private network access is provided in Appendix D.

4.2.5. Managed Identity

Azure Managed Identities eliminate the need for embedding secrets in application code. Managed Identity is another key module that embodies security-by-design principles. Rather than relying on hard-coded secrets or application credentials, the project provisions Azure User-Assigned Managed Identities. These identities enable services to authenticate securely with Azure resources, supporting the principle of least privilege and aligning with zero-trust architectures. By isolating identity provisioning in a dedicated module, the design promotes reuse and consistent access management across all deployed environments. The Container App is provisioned with a user-assigned Managed Identity, allowing it to achieve the following:
-
Secure authentication to Azure services such as PostgreSQL and Azure AI Search;
-
Bicep definition, including creating a Managed Identity at deployment, ensuring secure practices by default;
-
Managed identity roles to secure access to resources in the environment on the subscription level.
The infrastructure provisioning includes a dedicated module for Azure User-Assigned Managed Identity (UAMI), which enables secure authentication to Azure services without storing credentials. Identity is assigned appropriate roles on a subscription level, following the principle of least privilege. The full Bicep implementation for creating the managed identity and assigning its roles (e.g., Contributor, Search Index Data Contributor, AcrPull) is provided in Appendix E.

4.2.6. Private Endpoints and DNS Zones

Private Endpoints are critical for enforcing network security. The Bicep deployment provisions private endpoints for the following elements:
-
The PostgreSQL Flexible Server;
-
Azure AI Search;
-
The Azure Container Registry (optional, if blocking public access).
Private DNS Zones are also created or linked to resolve these private endpoints automatically within the VNet. Bicep modules ensure the following:
-
Creation and association of DNS Zones with the Vnet;
-
Configuration of necessary A records for Private Endpoint IP addresses;
-
All Private Endpoints are part of the relevant resource module.
To enforce strict network isolation and eliminate public access to PaaS services, the infrastructure leverages Azure Private DNS Zones linked to the virtual network. This enables automatic name resolution of private endpoints for services like PostgreSQL, Azure AI Search, and Azure Content Safety. The Bicep code for provisioning and linking these Private DNS Zones is included in Appendix F.
This design guarantees that all inter-service communication occurs privately and securely.

4.2.7. Azure Container Registry

Azure Container Registry (ACR) is used to store the container images for the application. The provisioning is a part of the deployment pipeline:
-
ACR instance with a chosen SKU (Basic or Premium, depending on the environment);
-
Optional private endpoint for network-restricted access;
-
Role assignments for Managed Identity or GitHub Actions to push/pull images.
ACR integration ensures the CI/CD pipeline can build, store, and deploy images securely [23].

4.3. Network Security Design

A key pillar of this solution is a robust, layered network security strategy designed to reduce the attack surface and enforce least-privilege access. By leveraging Azure-native networking features such as subnets, delegated subnets, Private Endpoints, and Private DNS Zones, the deployment ensures that all resources communicate securely over Azure’s backbone network, avoiding exposure to the public internet wherever feasible.

4.3.1. Subnets and Segmentation

Network segmentation is a fundamental security principle that minimizes lateral movement in the event of a breach. In this architecture, the Virtual Network (VNet) is defined with multiple subnets, detailed as follows, to separate workloads logically:
-
Application subnet, which hosts containerized workloads (Azure Container Apps);
-
Data subnet, which is reserved for stateful services such as PostgreSQL Flexible Server;
-
Private Endpoint subnet, which is dedicated to Private Endpoints.
This separation enables granular control over network security rules and supports future enhancements, such as Network Security Groups (NSGs) and route tables. By isolating the app layer from the data layer, potential vulnerabilities in one component do not automatically compromise other components.

4.3.2. Delegated Subnets

Certain Azure PaaS services require delegated subnets to function. For example, Azure Container Apps Environments manage networking resources within the assigned subnet. Delegation allows Azure to provision and manage the required infrastructure without compromising the broader VNet configuration. Delegated subnets represent an evolution of Azure’s PaaS integration strategy, offering the benefits of multi-tenancy and platform management while respecting customer-controlled network boundaries.

4.3.3. Private Endpoints and Private DNS Zones

One of the most significant security enhancements in modern Azure architectures is Private Link, which enables private connectivity to Azure PaaS resources. Private Endpoints create a network interface in the customer’s VNet, mapped to the service resource, effectively making it accessible via an internal IP address. Eliminate public ingress for all critical resources.
Private DNS Zones automate name resolution for Private Link connections, removing the need for manual IP management or custom DNS servers. Key benefits include the following:
-
Automatic resolution of service FQDNs to private IPs;
-
Simplified deployment and maintenance;
-
Fully private network communication.
This combination of subnets, delegated subnets, Private Endpoints, and Private DNS Zones represents an industry-standard approach for securing cloud-native deployments.
By ensuring no public ingress to critical data stores and minimizing exposure, the design aligns with the zero-trust security model promoted by Microsoft and industry frameworks, such as the NIST framework.

4.4. Parameterization for Environments

Consistent deployments across multiple environments (Dev, QA and Prod) are one of the most important goals of infrastructure as code. Each environment typically has unique configuration needs, such as different IP address ranges, instance sizes, and credentials.
This project uses Bicep’s parameter files feature to ensure maximum reusability of the core template logic while customizing values per environment. The main Bicep modules do not hard-code values for names, locations, SKUs, or credentials. Instead, they define parameters, making the infrastructure definition highly reusable, as shown in Figure 3. Typical differences between development, QA, and production environments include network segregation to ensure no overlapping networks and subnets, as well as SKU sizes, i.e., lower-cost and smaller SKUs in development and production-grade SKUs in production. Additionally, resource-naming conventions are used to avoid collisions and ensure traceability [8,19].
Parameterization represents the heart of infrastructure as code maturity. It enables teams to achieve environment parity, reduces manual errors, and supports an authentic DevOps culture where infrastructure deployments are repeatable, auditable, and secure.
By adopting a parameter-driven approach in Bicep, this project showcases a production-ready design that can adapt to organizational scaling needs while maintaining high security and consistency [5,20].

5. Bicep Modules’ Design

Programmable infrastructure has become a critical enabler of modern cloud-based systems, transforming how organizations design, deploy, and maintain their infrastructure. A central tenet of successful IaC implementation is modularity—the decomposition of infrastructure definitions into logically cohesive, reusable components. In this project, the use of Azure Bicep has been deliberately structured around a modular design to maximize maintainability, security, and collaboration. In addition to its engineering implementation focus, this section provides a methodological contribution by formalizing a reusable DevSecOps pipeline using GitHub Actions, with emphasis on modularity, security, and parameterized scalability.

5.1. Modular Approach

The motivation for adopting a modular approach in software-defined infrastructure stems from challenges inherent in managing complex cloud environments. A single, monolithic template might initially appear simpler to maintain, particularly for smaller applications with limited resources. As systems grow in complexity, spanning multiple networking components, databases, security configurations, and application services, the disadvantages of monolithic designs become evident. Large, unstructured templates are difficult to read, challenging to review or test, and prone to introducing errors during iterative development.
Splitting infrastructure code into modules addresses these challenges by enforcing the separation of concerns. Each module encapsulates the definition, parameters, and outputs of a specific resource or related set of resources. This decomposition aligns well with established software engineering practices, where complex systems are broken down into smaller, more manageable components. In doing so, modules become reusable across projects, promote consistent design patterns, and enable teams to work in parallel on different infrastructure components without frequent conflicts in version control systems [24].
Furthermore, a modular approach aligns with the principles of the Cloud Adoption Framework, as advocated for by Microsoft and other industry leaders, which emphasizes the need for consistent, maintainable, and policy-compliant infrastructure deployments. It also facilitates governance, as modules can be centrally reviewed, approved, and versioned, ensuring compliance with organizational standards across all environments.

5.2. Main Orchestration (main.bicep)

In the architectural design of this automated infrastructure provisioning solution, the primary focus is on the Bicep file, which serves as the orchestration layer that binds individual modules into a cohesive whole. Rather than defining every Azure resource directly, the main file is responsible for specifying deployment parameters, setting environment-level configurations, and invoking modules with appropriate inputs.
The main orchestration module (main.bicep) coordinates the deployment of all individual infrastructure components. It imports and links reusable Bicep modules for networking, identity, search services, container hosting, databases, and DNS configuration.
This central module manages parameter injection, output propagation, and inter-module dependencies. The full Bicep orchestration file is available in Appendix G.
This orchestration strategy enables a high degree of flexibility. Environment-specific parameters, such as region, address space, and SKU selection, are defined at the orchestration level, rather than being hard-coded within modules. This parameterization ensures that the same modules can be deployed to different environments, with differences handled through external parameter files. Consequently, teams can maintain a single source of truth for infrastructure design while customizing deployments to match the cost, performance, and compliance needs of each environment.
The orchestration layer enhances the visibility and traceability of the overall deployment topology. By defining explicit module invocations and their dependencies, the main module .bicep serves as living documentation of the system’s architecture, improving maintainability and supporting onboarding for new team members [24,25].

5.3. Security Practices in Infrastructure Modules

Security is a first-class concern in modern cloud deployments, and this Bicep design explicitly incorporates security considerations at multiple levels. Infrastructure as Code presents both opportunities and risks. While it enables the consistent and repeatable deployment of secure configurations, it can also codify insecure defaults if not carefully designed and implemented.
A critical security consideration in this design is the management of secrets. The Bicep modules are designed to avoid storing secrets directly in code. Instead, parameters such as passwords are injected at deployment time, typically sourced from secure locations such as Azure Key Vault or pipeline secrets in GitHub Actions. This design ensures that sensitive values are never committed to source control, significantly reducing the risk of credential leakage.
Role-based access control (RBAC) is another foundational security principle embodied in the design. By provisioning User-Assigned Managed Identities, the system enables Azure services to authenticate without secrets while supporting fine-grained access control through RBAC assignments. Managed Identities can be granted only the specific permissions they require; one example is access to Key Vault secrets or Cognitive Search indexes, enforcing the principle of least privilege. This modular RBAC configuration can be audited and modified independently, supporting continuous improvement of security posture [26].
Networking security is also tightly integrated into the design using Private Endpoints and subnet isolation. By ensuring that critical services such as PostgreSQL and Cognitive Search are reachable only over Azure’s private network, the architecture reduces the attack surface exposed to the public internet. The use of delegated subnets for Container Apps ensures that only authorized services can deploy into specific network segments, providing an additional layer of control and governance.
Lastly, the modular structure itself supports secure development practices. By isolating concerns, security-sensitive modules such as identity provisioning or networking can be reviewed, approved, and maintained independently of application-level deployments. This separation enables organizations to enforce rigorous security standards without impeding development velocity for other teams.
In summary, the Bicep modules’ design exemplifies a structured, modular, and secure approach to programmable infrastructure. By adopting well-defined modules for networking, identity, database, application hosting, and search services, the solution promotes maintainability, reusability, and strong security guarantees. The design aligns with industry best practices for cloud architecture, supporting the deployment of production-ready, scalable, and secure infrastructure on Azure while enabling teams to adapt deployments to the needs of development, QA, and production environments [13,27].

6. GitHub Actions CI/CD Pipelines

Automation is the cornerstone of modern DevOps practices, providing the repeatability, reliability, and auditability required for deploying cloud infrastructure at scale. GitHub Actions has been chosen as the CI/CD platform for orchestrating the entire deployment lifecycle of the application and its Azure infrastructure. To further illustrate the operational benefits of infrastructure as code and automation, it is helpful to compare performance metrics between traditional manual deployments and the automated deployment pipeline implemented in this project. The section extends beyond operational description by offering empirical data for evaluating automation efficiency, comparing deployment time, reliability, and manual error rates, thus contributing to reproducible cloud engineering research.
Manual deployment, typically performed through the Azure portal or CLI tools, requires a series of repetitive and error-prone tasks such as manual configuration, environment setup, dependency resolution, and verification. In practice, this process can take up to a few full working days to complete, depending on the complexity of the infrastructure and the availability of skilled personnel. In contrast, the automated pipeline developed using Azure Bicep and GitHub Actions executes the same end-to-end deployment in approximately 15 min, with no human intervention required. This time reduction to just 15 min demonstrates the dramatic efficiency gains enabled by IaC and CI/CD practices.
In terms of reliability and consistency, manual processes are also susceptible to configuration drift and deployment failures. Across several real-world scenarios, it was observed that manual deployments often result in misconfigured environments or incomplete resource provisioning, with an estimated failure or deviation rate of approximately 30%. These issues typically arise due to skipped steps, inconsistent parameter values, or differences between development and production environments. On the other hand, automated deployments executed through declarative templates and version-controlled workflows demonstrated a 1% failure rate during repeated execution. The use of Bicep ensured that infrastructure definitions were deterministic and idempotent, reducing the possibility of human error and enabling predictable outcomes across all environments.
This comparison highlights the tangible advantages of infrastructure automation, not only in terms of deployment speed but also in reducing operational risk, improving reproducibility, and supporting continuous delivery on a large scale.
This section provides a detailed description of the design, implementation, and operational principles of the two primary workflows used in the solution: deployment and deletion. It also examines the prerequisites for configuring secure access to Azure and details how secrets are managed within GitHub to enforce security best practices [28].

6.1. Prerequisites and Setup

Before a GitHub Actions workflow can deploy infrastructure to Azure, it must authenticate with sufficient privileges to create and manage resources. The recommended approach is to use an Azure service principal with role-based access control (RBAC) to manage access. To prepare for deployment automation, the following steps are required.
Creation of a Service Principal: The service principal (SPN) acts as a non-human identity that GitHub Actions uses to authenticate against Azure.
Assignment of Appropriate Roles: The SPN should have the Owner role on the target subscription or resource group. For security best practice, this can be further scoped to specific resource groups to implement the principle of least privilege.
Configuration of GitHub Secrets: These credentials should never be hard-coded in YAML or source files. Instead, they must be stored securely as GitHub secrets, accessible only to authorized workflows in the repository.

6.2. GitHub Secrets’ Structure

Secure management of credentials is fundamental in CI/CD systems. In this project, GitHub Actions workflows rely on environment secrets to inject sensitive information securely into the runtime environment of the pipeline.
The following secrets are configured in GitHub to support the workflows:
-
AZURE_CREDENTIALS—map, hash table;
 {“clientId”: “xxx-xxx-xxx”,
  “clientSecret”: “xxx-xxx-xxx”,
  “subscriptionId”: “xxx-xxx-xxx”,
  “tenantId”: “xxx-xxx-xxx”}
-
AZURE_CLIENT_SECRET—string, SPN secret;
-
AZURE_CLIENT_ID—string, SPN client ID;
-
AZURE_SUBSCRIPTION—string, Azure Subscription ID;
-
PG_PASSWORD—string between 8 and 128 characters long including characters from at least three of the following categories: uppercase letters, lowercase letters, numbers, and non-alphanumeric characters;
-
PG_USER—string, PSQL flex server username.

6.3. GitHub Actions Workflows

GitHub Actions enables declarative, YAML-based automation directly in a Git repository. Workflows are triggered by events (such as pushes, pull requests, or manual triggers) and define jobs composed of sequential steps. This project uses two carefully designed workflows, detailed as follows.

6.3.1. Deployment Workflow (deploy-multi-infra.yml)

The deployment pipeline orchestrates the complete process of building; approximating how much time it would take to complete; packaging; and deploying the application alongside provisioning its required Azure infrastructure, as shown in Figure 4.
At a high level, this workflow involves the following stages.
-
Checking out the Repository: The workflow begins by fetching the latest code from the repository. This ensures both the application code and infrastructure as code (Bicep templates) are available to the pipeline.
-
Azure Login: Authentication consumes the secret. This step establishes a secure CLI session against the Azure subscription, scoped to the permissions of the service principal.
-
Resource Group Creation or Validation: The pipeline ensures the target Azure Resource Group exists (or creates it if absent).
-
Container Image Building and Pushing: One of the distinguishing features of this pipeline is that it integrates application deployment with infrastructure provisioning. The container image is built from source. It is then pushed to Azure Container Registry (ACR), ensuring that the deployed container app always references a reproducible artifact.
-
Bicep Deployment: This step deploys the infrastructure described in Bicep, injecting environment-specific parameters. The result is a fully provisioned Azure environment, including Virtual Networks, Container Apps, PostgreSQL Flexible Server, Managed Identities, Azure AI Search, Private Endpoints, DNS Zones, and ACR integration. By integrating the build, push, and deploy stages, the workflow achieves application-centric infrastructure deployments, aligning with best practices for cloud-native development.
The deployment pipeline is implemented via a GitHub Actions workflow that automates the provisioning of both the infrastructure and containerized application. It supports dynamic targeting of ACR and infrastructure components across environments (dev, QA, prod). The full workflow definition (deploy-multi-infra.yml) is included in Appendix H.

6.3.2. Deletion Workflow (delete-infra.yml)

Complementing the deployment pipeline is the deletion workflow, which enforces complete lifecycle management of infrastructure. Infrastructure as code is not just about provisioning but also about safe, reliable, and auditable teardown. The deletion workflow ensures that resources can be cleanly removed when they are no longer needed, thereby avoiding orphaned resources, unexpected costs, and security liabilities. The design ensures that the infrastructure lifecycle is fully automated from creation to destruction, enabling ephemeral environments for development and testing that mirror production with minimal manual effort, as shown in Figure 5 [29].
Workflow steps:
-
Checking out the Repository, which retrieves any required configuration;
-
Azure Login, which authenticates securely using the same credentials, ensuring only authorized SPN can initiate deletions;
-
Removing Managed Identity roles and Resource Group Deletion, which removes the MI-assigned roles and then deletes the entire resource group and all contained resources, providing a predictable and complete cleanup process. The process allows the pipeline to finish immediately while the deletion proceeds asynchronously in Azure.
A dedicated deletion workflow ensures the clean and secure teardown of infrastructure components once they are no longer needed. This workflow removes role assignments, deletes the managed identity, and destroys resource groups used for ACR and infrastructure.
The full delete-infra.yml GitHub Actions workflow is provided in Appendix I.
Both workflows utilize the workflow_dispatch trigger, enabling manual and auditable releases. This choice enables teams to carefully control when infrastructure changes occur in different environments (development, QA, production).

6.4. Security Considerations

A critical requirement for any automated infrastructure deployment pipeline is to ensure that security is not compromised in pursuit of speed and automation. In cloud environments, mismanaged credentials, overly broad permissions, and poor secrets management are frequent root causes of breaches. Therefore, a secure CI/CD design must explicitly address these risks by enforcing least privilege and auditable access controls throughout the deployment pipeline. In Azure, automation pipelines authenticate using service principal application identities registered in Azure Active Directory, which can be granted permissions through Role-Based Access Control (RBAC). It is a fundamental best practice to grant only the permissions required for the automation tasks. For this project, the service principal is assigned the Owner role, which enables the creation and management of resources within a defined scope. Another pillar of credential security is regular rotation. Storing long-lived secrets in GitHub without rotation increases the window of opportunity for exploitation in case of a leak. Secret rotation is not just a recommended practice; it is a requirement for compliance in many regulated industries, ensuring that even if a secret is exposed, its usefulness is time-restricted. GitHub provides encrypted secrets that are only decrypted at runtime within the context of a workflow execution. This design ensures secrets are not exposed in the repository’s history or pull requests. These measures align with Microsoft’s recommended guidelines for secure automation in Azure, supporting both operational efficiency and robust protection against modern threat scenarios. By building security into the CI/CD pipeline itself, organizations can achieve true DevSecOps, where security is an integrated, automated, and auditable part of every deployment [30,31].

7. Discussion

Designing and deploying an automated, Bicep-driven infrastructure pipeline in GitHub for Azure represents a modern, highly maintainable approach to cloud infrastructure management. This section critically examines the overall strategy by analyzing its strengths, recognizing its challenges and limitations, and proposing future improvements that can increase the robustness, security, and maintainability of the solution. The approach of combining Azure Bicep and GitHub Actions delivers a modern, modular, and automated infrastructure deployment solution tailored to Azure’s capabilities. It offers strong benefits in maintainability, reproducibility, and security alignment with DevOps practices. It also introduces challenges that require ongoing operational discipline, particularly in areas such as security, complexity management, and knowledge development. By acknowledging these limitations and planning targeted improvements, such as automated testing, secrets rotation, and cost controls, teams can evolve this foundation into an even more robust, secure, and efficient platform for delivering cloud-native applications at scale [32].

7.1. Strengths of the Approach

One of the core strengths of this approach lies in its modularity, achieved through Bicep’s support for reusable modules. By segmenting the infrastructure definitions into discrete, purpose-specific modules (networking, container app, database), the project enables teams to maintain, test, and evolve individual components in isolation. This modular design simplifies onboarding for new team members and reduces the cognitive load required to understand the full infrastructure stack. Instead of wrestling with thousands of lines of monolithic ARM JSON templates, teams can reason about small, well-defined Bicep modules with clear interfaces and dependencies.
Another notable strength is the level of automation embedded throughout the deployment process. By leveraging GitHub Actions as the CI/CD platform, infrastructure changes are deployed consistently, auditably, and repeatably. Developers can trigger deployments through familiar Git workflows (merges to a main branch or protected environment branches), eliminating the need for manual portal-driven provisioning that is error-prone and difficult to audit. This automation aligns closely with DevOps principles, reducing lead time for changes and ensuring infrastructure is always defined in code, version-controlled, and reproducible.
Reproducibility itself is a critical benefit of infrastructure as code. The use of parameter files and environment-scoped configurations enables the reliable instantiation of development, QA, and production environments with environment-specific settings, while sharing a common code base. This reduces configuration drift and simplifies debugging, as developers can recreate an environment from scratch and know it will match its definition. Reproducibility also improves disaster recovery preparedness, as teams can redeploy infrastructure quickly if needed [33].
Furthermore, the choice of Bicep specifically brings significant benefits over traditional ARM Templates. Bicep’s concise, readable syntax improves maintainability and reduces the likelihood of introducing errors due to excessive complexity or nesting. Its native support in Azure and automatic transformation to ARM templates ensure first-class integration without introducing external dependencies or runtime tools.
The integration of GitHub Actions offers additional advantages. As a cloud-native, widely adopted CI/CD platform, GitHub Actions provides flexibility in designing sophisticated workflows, integrating with secrets management, and supporting manual approvals and branch protections. Teams benefit from tight integration with the GitHub ecosystem, including pull request reviews, issues, and auditing features, creating a seamless DevSecOps workflow.
In combination, these strengths deliver an infrastructure deployment process that is traceable, scalable, secure, and maintainable, key requirements for modern cloud-native applications.

7.2. Challenges and Limitations

Despite these strengths, the approach is not without challenges and limitations.
A primary concern is the maturity of Azure Bicep itself. While Bicep has advanced rapidly since its introduction and is now a supported, production-ready tool, it is relatively new compared to alternatives like Terraform or AWS CloudFormation. As such, the ecosystem for modules, community support, and learning resources is still growing. Certain advanced Azure features or resource types may lag in Bicep support compared to ARM JSON or may require careful workarounds. For teams adopting Bicep, this can mean investing time in staying up to date with the latest releases and practices to ensure compatibility and avoid limitations.
Additionally, Bicep’s Azure-only focus is both a strength and a limitation. While this design ensures deep integration with Azure’s native capabilities, it prevents truly cloud-agnostic deployments. Organizations considering multi-cloud strategies or hybrid deployments may find Bicep insufficient on its own; they may therefore need to integrate other IaC tools to support multiple providers.
Another challenge lies in the learning curve associated with introducing programmable infrastructure practices to teams that are new to DevOps or Azure. While Bicep is simpler than ARM JSON, it still requires an understanding of Azure resources, RBAC, networking, and best practices for secure deployment. Similarly, configuring GitHub Actions securely demands familiarity with secret management, branch protection, and role separation to avoid introducing security vulnerabilities. These skills may not be immediately available in all organizations and require investment in training and documentation [34].
Pipeline complexity can also grow as environments and requirements expand. Managing multiple parameter files, secrets, and environment-specific configurations in GitHub Actions can become challenging, especially for organizations with strict security or compliance requirements. Without careful design, pipelines can become brittle or hard to maintain.
Finally, while the solution improves security compared to manual deployments, secret management in GitHub Actions still requires a high level of operational discipline. Secrets must be rotated, scoped carefully, and protected with branch and environment policies to reduce the risks of exposure or misuse.

7.3. Goal Evaluation and Efficiency Overview

The implementation presented in this paper successfully fulfills the primary goals outlined in Section 3.3, particularly in terms of security, consistency, and automation. Modular Bicep templates, environment-specific parameterization, and GitHub Actions pipelines contribute to a reproducible and secure infrastructure deployment model.
From a performance standpoint, automated deployments consistently completed in under 15 min across all tested environments, reducing manual setup time by over 80%. Error rates decreased from approximately 30% in manual runs to less than 1% post-automation. These empirical outcomes, detailed in Section 6, demonstrate measurable gains in reliability and operational speed.
While cost optimization was not quantitatively assessed in this study, the architecture supports ephemeral environments and automated teardown, enabling organizations to minimize idle resource expenditure. Future work will incorporate detailed cost–performance benchmarking based on Azure usage analytics.

7.4. Future Improvements

To address these challenges and further strengthen the approach, several future improvements can be considered.
First, introducing automated testing for infrastructure deployments can greatly improve confidence and reliability. Tools such as Azure Resource Manager (ARM) What-If deployments, Bicep Linter, and integration tests can be added to the CI pipeline to validate templates before deployment. This reduces the risk of breaking changes and enables teams to catch errors earlier in the development cycle.
Second, Policy as Code is a powerful addition that enables the automatic enforcement of compliance and security standards. Azure Policy can be defined and deployed as code to prevent configuration drift and enforce organizational requirements such as allowed locations, SKU restrictions, or security configurations. Integrating policy checks into the CI/CD pipeline ensures that only compliant resources are deployed, reducing manual review effort and increasing security posture.
Another area for improvement is cost optimization. As cloud usage grows, controlling costs becomes critical. Teams can integrate Azure Cost Management APIs or third-party tools into their workflows to estimate costs before deployment, monitor spending, and enforce budgets. For example, workflows can include steps to validate that requested resources meet cost thresholds or automatically tag resources for cost tracking. By incorporating cost optimization into the deployment process, organizations can avoid unexpected bills and promote responsible cloud usage [35].
Improved secret management is another avenue for enhancement. While GitHub Secrets provides encrypted storage, integrating with Azure Key Vault can offer greater control, automated rotation, and enhanced auditing capabilities. GitHub Actions supports fetching secrets from the Key Vault at runtime, ensuring that secrets do not remain in the GitHub repository itself. This also simplifies rotation processes and aligns with best practices for managing high-value credentials.
Furthermore, environmental drift detection can be introduced. Tools such as Azure Resource Graph or manual Azure CLI queries can be used to validate that deployed resources match the defined state. This helps to detect and correct manual changes in production that bypass the pipeline, preserving the benefits of software-defined infrastructure.
Finally, team collaboration and documentation can be enhanced. While code provides a source of truth, human-readable documentation describing the architecture, modules, and deployment process is vital for onboarding, auditing, and knowledge sharing. Automated documentation generation from Bicep files or GitHub Actions workflows can help keep this information up to date and accessible.

8. Conclusions

As organizations increasingly rely on cloud-native architectures to deliver business value with speed, reliability, and security, the importance of infrastructure as code and automated deployment pipelines cannot be overstated. This paper aimed to explore and demonstrate a modern approach to building, managing, and deploying Azure cloud infrastructure for an application using Azure Bicep and GitHub Actions. Through a structured, modular, and automated process, this project aimed to address real-world challenges in environmental reproducibility, security, and operational efficiency.
At the outset, the project’s primary goal was to design an end-to-end pipeline that enables teams to provision complete Azure environments from networking and compute to databases and AI-powered search services using declarative, version-controlled Bicep templates. A key requirement was to ensure the solution supports multiple deployment environments with environment-specific parameterization while enforcing consistent configurations and security standards.
The achievements of this approach are significant. First, by adopting Azure Bicep as the IaC language, the project benefits from a highly readable, modular, and maintainable way of defining infrastructure. Compared to traditional ARM templates, Bicep significantly reduces boilerplate code and complexity, supporting a clear separation of concerns through reusable modules designed to be independently manageable, which promotes both code quality and operational flexibility.
Second, integrating GitHub Actions as the CI/CD automation platform provides seamless, developer-friendly workflows that are tightly integrated with Git version control. Automated pipelines for both deployment and deletion of environments ensure consistency and reduce human error, while enabling a traceable and auditable change history. These pipelines demonstrate a practical approach to continuous delivery of infrastructure changes, supporting the broader DevOps goal of shortening lead times while increasing deployment reliability.
Importantly, the solution also emphasizes security best practices at multiple levels. Secrets, such as service principal credentials and database passwords, are managed through GitHub’s encrypted secrets store, thereby avoiding the risk of hard-coded credentials. Role-based access control is enforced by granting the service principal only the permissions necessary to deploy into defined Azure resource groups, thereby minimizing the blast radius in the event of a compromise. By integrating secret rotation strategies and enforcing disciplined workflows, the approach aligns with Microsoft’s security recommendations for automated deployments.
Beyond its technical implementation, the project demonstrates the business value of automating infrastructure provisioning in the cloud. By codifying infrastructure as declarative templates, teams gain the ability to create consistent, repeatable environments on demand, a crucial capability for supporting agile development, testing, and release cycles. This reduces configuration drift between environments, simplifies disaster recovery planning, and provides transparency for audits and compliance reviews. In short, it delivers the operational scalability required for modern software delivery while reducing manual overhead and risk.
While the strengths of the solution are clear, this paper also recognizes the challenges and limitations inherent to the approach. Azure Bicep, while powerful and rapidly maturing, is still evolving, with occasional gaps in feature parity compared to ARM or third-party tools like Terraform. This requires teams to remain vigilant about updates and best practices. Similarly, introducing IaC practices demands investment in training and cultural change within organizations, particularly for teams new to DevOps principles or unfamiliar with Azure’s security model.
Another critical consideration is pipeline complexity. As environments, regions, and regulatory requirements grow, so too will the complexity of deployment workflows and parameter management. Without transparent governance and disciplined practices, there is a risk that pipelines will become brittle or insecure. The paper proposes mitigation strategies, such as automated testing of templates, policy-as-code enforcement, and integrating the Azure Key Vault for secrets’ management, to help address these challenges.
Looking forward, the approach described here offers a solid foundation for further evolution. Future improvements might include richer validation and linting for Bicep modules, automated integration tests for deployed resources, enforcement of organizational policies through Azure Policy, and better cost visibility via integrated cost management tools. Additionally, adopting a holistic DevSecOps mindset where security is embedded throughout the pipeline will further strengthen the solution’s resilience and compliance.
Ultimately, this project demonstrates that combining Azure Bicep and GitHub Actions offers a powerful and modern approach to managing cloud infrastructure on Azure. It enables teams to move beyond ad hoc, manually provisioned resources to an automated, repeatable, and secure deployment model that aligns with best practices in cloud engineering and DevOps. The result is not only greater operational efficiency but also increased confidence in the security, maintainability, and scalability of the cloud environments supporting critical business applications.
In conclusion, this study underscores the critical role of infrastructure as code in transforming how organizations design, deploy, and manage cloud infrastructure. By adopting a modular, automated approach with Bicep and GitHub Actions, development teams can accelerate delivery while maintaining strong security and governance. As cloud adoption continues to grow, these practices will become essential for any organization seeking to remain competitive, agile, and secure in an increasingly complex digital landscape.

Author Contributions

V.M., D.G., and N.H. were involved in the entire process of producing this paper, including conceptualization, methodology, modeling, validation, visualization, and manuscript preparation. All authors have read and agreed to the published version of the manuscript.

Funding

This work has been accomplished with financial support from the European Regional Development Fund within the Operational Program “Bulgarian National Recovery and Resilience Plan”, the procedure for the direct provision of grants “Establishing a network of research higher education institutions in Bulgaria”, and under Project BG-RRP-2.004-0005, “Improving the research capacity and quality to achieve international recognition and resilience of TU-Sofia (IDEAS)”.

Data Availability Statement

The original contributions presented in this study are included in the article. Further inquiries can be directed to the corresponding author.

Conflicts of Interest

The authors declare that they have no conflicts of interest.

Appendix A. Virtual Network Bicep Module

The following Bicep module defines a reusable and parameterized template for deploying an Azure Virtual Network (VNet) with configurable subnets. It supports delegation to service-specific resources when required and outputs relevant identifiers for use in downstream modules. The design ensures reusability across environments and aligns with software-defined infrastructure practices.
param vnetName string
param location string
param addressPrefix string
param subnets array

resource vnet ‘Microsoft.Network/virtualNetworks@2023-11-01’ = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [addressPrefix]
      }
    subnets: [
      for subnet in subnets: {
        name: subnet.name
        properties: union({
          addressPrefix: subnet.prefix
        }, contains(subnet, ‘delegated’) && subnet.delegated != ‘’ ? {
          delegations: [
        {
              name: ‘${subnet.name}-delegation’
              properties: {
                serviceName: subnet.delegated
              }
            }
          ]
        } : {})
      }
    ]
  }
}

output subnetNames array = [for subnet in subnets: subnet.name]
output subnetIds array = [
  for subnet in subnets: resourceId(‘Microsoft.Network/virtualNetworks/subnets’, vnet.name, subnet.name)
]
output vnetId string = vnet.id
output vnetName string = vnet.name

Appendix B. Full Azure Container App Bicep Module for Secure Deployment

The following template defines a complete Azure Container App deployment using Bicep. It includes identity binding, environment variable injection, secrets, and integration with PostgreSQL and Azure Search. The module is intended for production-grade deployments and supports parameterized reuse across environments.
param containerAppName string
param location string
param containerAppImage string
param environmentId string
param managedIdentityId string
param managedIdentityClientId string
@secure()
param postgresAdminUser string
@secure()
param postgresAdminPassword string
param postgresServerName string
param searchServiceEndpoint string
param acrLoginServer string

resource containerApp ‘Microsoft.App/containerApps@2024-10-02-preview’ = {
  name: containerAppName
  location: location
  identity: {
    type: ‘UserAssigned’
    userAssignedIdentities: {
      ‘${managedIdentityId}’: {}
    }
  }
  properties: {
    template: {
      containers: [
        {
          name: ‘app-container’
          image: containerAppImage
          resources: {
            cpu: 32
            memory: ‘256Gi’
          }
          env: [
          {
              name: ‘PG_USER’
              secretRef: ‘postgres-username’
            }
            {
              name: ‘PG_PASSWORD’
              secretRef: ”postgres-password‘
            }
            {
              name: ‘PG_HOST’
              value: ‘${postgresServerName}.postgres.database.azure.com’
            }
            {
              name: ‘PG_DB’
              value: ”llm_database‘
            }
            {
              name: ‘PG_PORT’
              value: ‘5432’
            }
            {
              name: ‘AZURE_MI_ID’
              value: managedIdentityClientId
            }
            {
              name: ‘AZURE_SEARCH_ENDPOINT’
              value: searchServiceEndpoint
            }
            {
              name: ‘AZURE_SEARCH_INDEX_NAME’
              value: ‘llm-index’
            }
          ]
        }
      ]
    }
    configuration: {
    ingress: {
        external: true
        targetPort: 80
        transport: ‘auto’
      }
      registries: [
        {
          identity: managedIdentityId
          server: acrLoginServer
        }
      ]
      secrets: [
        {
          name: ‘postgres-username’
          value: postgresAdminUser
        }
        {
          name: ‘postgres-password’
          value: postgresAdminPassword
        }
      ]
    }
    environmentId: environmentId
  }
}

Appendix C. Secure PostgreSQL Flexible Server Deployment Template (Bicep)

This appendix provides a full Bicep template for deploying a PostgreSQL Flexible Server with enhanced security features. The configuration disables public access, leverages delegated subnets for VNet integration, and uses a Private DNS Zone. It is suitable for production and development environments where database isolation is critical.
param location string
param postgresServerName string
param postgresAdminUser string
@secure()
param postgresAdminPassword string
param dnsZonePsqlId string
param psqlDelegatedSubnetId string

resource flexibleServer ‘Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01’ = {
  name: postgresServerName
  location: location
  properties: {
    administratorLogin: postgresAdminUser
    administratorLoginPassword: postgresAdminPassword
    version: ‘13’
    availabilityZone: ‘1’
    storage: {
      storageSizeGB: 128
    }
    network: {
      publicNetworkAccess: ‘Disabled’
      delegatedSubnetResourceId: psqlDelegatedSubnetId
      privateDnsZoneArmResourceId: dnsZonePsqlId
    }
  }
  sku: {
    name: ‘Standard_D2s_v3’
    tier: ‘GeneralPurpose’
  }
}

resource postgresDatabase ‘Microsoft.DBforPostgreSQL/flexibleServers/databases@2022-12-01’ = {
  name: ‘environment-db’
  parent: flexibleServer
  properties: {}
}

output postgresServerId string = flexibleServer.id

Appendix D. Private Azure Cognitive Search Deployment (Bicep)

This appendix provides the full Bicep deployment template for provisioning an Azure Cognitive Search service with private network connectivity. Public access is disabled, and the resource is connected to a private subnet and DNS Zone, ensuring internal-only access. The configuration supports integration in highly secure environments such as enterprise-grade APIs or internal LLM applications.
param searchServiceName string
param location string
param sku string = ‘basic’
param privateendpointsubnetId string
param dnsZoneAiSearchId string

resource search ‘Microsoft.Search/searchServices@2023-11-01’ = {
  name: searchServiceName
  location: location
  sku: {
    name: sku
  }
  properties: {
    publicNetworkAccess: ‘disabled’
    networkRuleSet: {}
    replicaCount: 1
    partitionCount: 1
    hostingMode: ‘default’
    authOptions: {
      aadOrApiKey: {
        aadAuthFailureMode: ‘http403’
      }
    }
  }
}

resource aiSearchPE ‘Microsoft.Network/privateEndpoints@2023-05-01’ = {
  name: ‘ai-search-private-endpoint’
  location: location
  properties: {
    subnet: {
      id: privateendpointsubnetId
    }
    privateLinkServiceConnections: [
      {
         name: ‘${searchServiceName}-pls-connection’
        properties: {
          privateLinkServiceId: search.id
          groupIds: [
            ‘searchService’
          ]
        }
      }
    ]
  }
}

resource privateDnsZoneGroup ‘Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-05-01’ = {
  name: ‘default’
  parent: aiSearchPE
  properties: {
    privateDnsZoneConfigs: [
      {
        name: ‘search-dns-config’
        properties: {
          privateDnsZoneId: dnsZoneAiSearchId
        }
      }
    ]
  }
}

output aiSearchPrivateEndpointId string = aiSearchPE.id
output aiSearchPrivateEndpointName string = aiSearchPE.name
output searchServiceId string = search.id
output searchServiceEndpoint string = ‘https://${search.name}.search.windows.net’

Appendix E. Bicep Template for Managed Identity Provisioning and Role Assignment

The following Bicep code defines the creation of a User-Assigned Managed Identity and assigns it specific Azure roles to access services such as PostgreSQL, Azure Cognitive Search, and Azure Container Registry.
param identityName string
param location string

resource userAssignedIdentity ‘Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31’ = {
  name: identityName
  location: location
}

output managedIdentityId string = userAssignedIdentity.id
output managedIdentityClientId string = userAssignedIdentity.properties.clientId
output managedIdentityPrincipalId string = userAssignedIdentity.properties.principalId
param managedIdentityPrincipalId string
targetScope = ‘subscription’

resource uaiRbacContributor ‘Microsoft.Authorization/roleAssignments@2022-04-01’ = {
  name: guid(‘containerAppManIdContributorRoleAssignment’, managedIdentityPrincipalId)
  scope: subscription()
  properties: {
    roleDefinitionId: subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, ‘b24988ac-6180-42a0-ab88-20f7382dd24c’) // Contributor
    principalId: managedIdentityPrincipalId
    principalType: ‘ServicePrincipal’
  }
}

resource uaiRbacAiSearch ‘Microsoft.Authorization/roleAssignments@2022-04-01’ = {
  name: guid(‘containerAppManIdSearchIndDataContrRoleAssignment’, managedIdentityPrincipalId)
  scope: subscription()
  properties: {
    roleDefinitionId: subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, ‘8ebe5a00-799e-43f5-93ac-243d3dce84a7’) // Search Index Data Contributor
    principalId: managedIdentityPrincipalId
    principalType: ‘ServicePrincipal’
  }
}

resource uaiRbacSearchContributor ‘Microsoft.Authorization/roleAssignments@2022-04-01’ = {
  name: guid(‘containerAppManIdSearchContributorRoleAssignment’, managedIdentityPrincipalId)
  scope: subscription()
  properties: {
    roleDefinitionId: subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, ‘7ca78c08-252a-4471-8644-bb5ff32d4ba0’) // Search Service Contributor
    principalId: managedIdentityPrincipalId
    principalType: ‘ServicePrincipal’
  }
}

resource uaiRbacAcrPull ‘Microsoft.Authorization/roleAssignments@2022-04-01’ = {
  name: guid(‘containerAppManIdAcrPullRoleAssignment’, managedIdentityPrincipalId)
  scope: subscription()
  properties: {
    roleDefinitionId: subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, ‘7f951dda-4ed3-4680-a7ca-43fe172d538d’) // AcrPull
    principalId: managedIdentityPrincipalId
    principalType: ‘ServicePrincipal’
  }
}

resource uaiRbacAcrPush ‘Microsoft.Authorization/roleAssignments@2022-04-01’ = {
  name: guid(‘containerAppManIdAcrPushRoleAssignment’, managedIdentityPrincipalId)
  scope: subscription()
  properties: {
    roleDefinitionId: subscriptionResourceId(‘Microsoft.Authorization/roleDefinitions’, ‘8311e382-0749-4cb8-b61a-304f252e45ec’) // AcrPush
    principalId: managedIdentityPrincipalId
    principalType: ‘ServicePrincipal’
  }
}

Appendix F. Bicep Template for Private DNS Zones and VNet Integration

This Bicep module defines the creation of Private DNS Zones for key Azure services and links them to the virtual network, enabling internal name resolution and secure service access.
param vnetName string
param vnetId string

// Private DNS zone for Azure PostgreSQL
resource dnsZonePsql ‘Microsoft.Network/privateDnsZones@2020-06-01’ = {
  name: ‘privatelink.postgres.database.azure.com’
  location: ‘global’
}

resource vnetLinkPsql ‘Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01’ = {
  name: ‘${vnetName}-link-psql’
  location: ‘global’
  parent: dnsZonePsql
  properties: {
    virtualNetwork: {
      id: vnetId
    }
    registrationEnabled: false
  }
}

/// Private DNS zone for Azure AI Search
resource dnsZoneAiSearch ‘Microsoft.Network/privateDnsZones@2020-06-01’ = {
  name: ‘privatelink.search.windows.net’
  location: ‘global’
}

resource vnetLinkAiSearch ‘Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01’ = {
  name: ‘${vnetName}-link-ai-search’
  location: ‘global’
  parent: dnsZoneAiSearch
  properties: {
    virtualNetwork: {
      id: vnetId
    }
    registrationEnabled: false
  }
}

/// Private DNS zone for Azure Content Safety
resource dnsZoneContentSafety ‘Microsoft.Network/privateDnsZones@2020-06-01’ = {
name: ‘privatelink.cognitiveservices.azure.com’
location: ‘global’
}

resource vnetLinkContentSafety ‘Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01’ = {
name: ‘${vnetName}-link-content-safety’
location: ‘global’
parent: dnsZoneContentSafety
properties: {
virtualNetwork: {
id: vnetId
}
registrationEnabled: false
}
}

// Outputs
output dnsZonePsqlId string = dnsZonePsql.id
output dnsZonePsqlName string = dnsZonePsql.name
output vnetLinkPsqlId string = vnetLinkPsql.id

output dnsZoneAiSearchId string = dnsZoneAiSearch.id
output dnsZoneAiSearchName string = dnsZoneAiSearch.name
output vnetLinkAiSearchId string = vnetLinkAiSearch.id

output dnsZoneContentSafetyId string = dnsZoneContentSafety.id
output dnsZoneContentSafetyName string = dnsZoneContentSafety.name
output vnetLinkContentSafetyId string = vnetLinkContentSafety.id

Appendix G. Main Bicep Orchestration Module

This orchestration file (main.bicep) ties together all infrastructure components using modular deployment practices. It defines top-level parameters and invokes child modules with appropriate inputs and outputs to form a cohesive deployment pipeline.
///////// PARAMETERS /////////
param location string
param vnetName string
param addressPrefix string
param subnets array
param environmentName string
param containerAppName string
param containerAppImage string
param identityName string
param postgresServerName string
param postgresAdminUser string
@secure()
param postgresAdminPassword string
param searchServiceName string
param searchSku string
param acrLoginServerName string

///////// VARIABLES /////////
var subnetNamesArray = [for s in subnets: s.name]
var appSubnetName = ‘app-subnet’
var appSubnetIndex = indexOf(subnetNamesArray, appSubnetName)
var appSubnetId = vnet.outputs.subnetIds[appSubnetIndex]
var psqlDelegatedSubnetName = ‘psql-delegated-subnet’
var psqlDelegatedSubnetIndex = indexOf(subnetNamesArray, psqlDelegatedSubnetName)
var psqlDelegatedSubnetId = vnet.outputs.subnetIds[psqlDelegatedSubnetIndex]
var privateendpointsubnetName = ‘private-endpoint-subnet’
var privateendpointsubnetIndex = indexOf(subnetNamesArray, privateendpointsubnetName)
var privateendpointsubnetId = vnet.outputs.subnetIds[privateendpointsubnetIndex]
var dnsZonePsqlId = privateDnsZone.outputs.dnsZonePsqlId
var managedIdentityPrincipalId = identityModule.outputs.managedIdentityPrincipalId

///////// RESOURCES /////////
// Module RBAC role assignments
module rbacRoles ‘resources/rbac-roles/rbacroles.bicep’ = {
  name: ‘deployRbacRoles’
  scope: subscription()
  params: {
    managedIdentityPrincipalId: managedIdentityPrincipalId
  }
}
// Module Managed identity
module identityModule ‘resources/managed-identity/managedidentity.bicep’ = {
  name: ‘deployManagedIdentity’
  params: {
    identityName: identityName
    location: location
  }
}
//// Module AI Search
module searchModule ‘resources/ai-search/search.bicep’ = {
  name: ‘deploySearchService’
  params: {
    searchServiceName: searchServiceName
    location: location
    sku: searchSku
    privateendpointsubnetId: privateendpointsubnetId
    dnsZoneAiSearchId: privateDnsZone.outputs.dnsZoneAiSearchId
  }
}
// Module Private DNS zone
module privateDnsZone ‘resources/private-dns-zones/dnszones.bicep’ = {
  name: ‘deployPrivateDnsZones’
  params: {
    vnetName: vnetName
    vnetId: vnet.outputs.vnetId
  }
}
// Module Virtual network
module vnet ‘resources/network/vnet.bicep’ = {
  name: ‘deployVnet’
  params: {
    vnetName: vnetName
    location: location
    addressPrefix: addressPrefix
    subnets: subnets
  }
}
// Module Container app
module containerAppModule ‘resources/container-app/containerapp.bicep’ = {
  name: ‘deployContainerApp’
  params: {
    containerAppName: containerAppName
    location: location
    containerAppImage: containerAppImage
    environmentId: appEnvModule.outputs.environmentId
    managedIdentityId: identityModule.outputs.managedIdentityId
    postgresAdminPassword: postgresAdminPassword
    postgresAdminUser: postgresAdminUser
    postgresServerName: postgresServerName
    managedIdentityClientId: identityModule.outputs.managedIdentityClientId
    searchServiceEndpoint: searchModule.outputs.searchServiceEndpoint
    acrLoginServer: acrLoginServerName
  }
}
// Module Container app environment
module appEnvModule ‘resources/app-env/appenv.bicep’ = {
  name: ‘deployAppEnv’
  params: {
    environmentName: environmentName
    location: location
    appSubnetId: appSubnetId
  }
}
// Module PostgreSQL flexible server
module psqlModule ‘resources/psql-flexible-server/flexibleserver.bicep’ = {
  name: ‘deployPSQLFlexServer’
  params: {
    location: location
    postgresServerName: postgresServerName
    postgresAdminUser: postgresAdminUser
    postgresAdminPassword: postgresAdminPassword
    psqlDelegatedSubnetId: psqlDelegatedSubnetId
    dnsZonePsqlId: dnsZonePsqlId
  }
}

///////// OUTPUTS /////////
output vnetName string = vnetName
output subnetNames array = vnet.outputs.subnetNames
output containerAppEnvironmentId string = appEnvModule.outputs.environmentId
output managedIdentityId string = identityModule.outputs.managedIdentityId
output managedIdentityClientId string = identityModule.outputs.managedIdentityClientId
output managedIdentityPrincipalId string = identityModule.outputs.managedIdentityPrincipalId
output searchServiceId string = searchModule.outputs.searchServiceId
output searchServiceEndpoint string = searchModule.outputs.searchServiceEndpoint

Appendix H. GitHub Actions Workflow for Infrastructure and Application Deployment

The deploy-multi-infra.yml file defines a GitHub Actions workflow used to deploy container images and Bicep-defined infrastructure. It supports parameterized execution for different environments and targets, enabling flexibility in CI/CD execution.
name: Deployment Workflow

on:
  workflow_dispatch:
    inputs:
      environment:
        description: ‘Target environment’
        required: true
        default: ‘dev’
        type: choice
        options:
          - dev
          - qa
          - prod
      target:
        description: ‘Target deployment scope’
        required: true
        default: ‘all’
        type: choice
        options:
          - infra
          - acr
          - all

jobs:
  Build-And-Push-Image:
    runs-on: ubuntu-latest
    environment: ${{ github.event.inputs.environment }}
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
    - name: Azure Login
      uses: azure/login@v2
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}
    - name: Ensure ACR RG Exists
      if: github.event.inputs.target == ‘acr’ || github.event.inputs.target == ‘all’
      run: |
        RG_EXISTS=$(az group exists --name ${{ github.event.inputs.environment }}-acr-rg)
        if [ "$RG_EXISTS" = true ]; then
          echo "Resource group exists."
        else
          echo "Resource group does not exist. Creating …"
        az group create \
          --name ${{ github.event.inputs.environment }}-acr-rg \
          --location ‘swedencentral’
          echo "Resource group ${{ github.event.inputs.environment }}-acr-rg created."
        fi
    - name: Ensure ACR exists
      if: github.event.inputs.target == ‘acr’ || github.event.inputs.target == ‘all’
      shell: bash
      run: |
        ACR_NAME=${{ github.event.inputs.environment }}azurecontainerregistry
        ACR_RG=${{ github.event.inputs.environment }}-acr-rg
        if az acr show --name "$ACR_NAME" --resource-group "$ACR_RG" &>/dev/null; then
          echo "ACR $ACR_NAME already exists."
        else
          echo "ACR $ACR_NAME not found, creating…"
          az acr create \
            --name "$ACR_NAME" \
            --resource-group "$ACR_RG" \
            --sku Premium \
            --location swedencentral
          echo "ACR $ACR_NAME created."
        fi
    - name: ACR Login
      if: github.event.inputs.target == ‘acr’ || github.event.inputs.target == ‘all’
      uses: docker/login-action@v3
      with:
        registry: ${{ github.event.inputs.environment }}azurecontainerregistry.azurecr.io
        username: ${{ secrets.AZURE_CLIENT_ID }}
        password: ${{ secrets.AZURE_CLIENT_SECRET }}
    - name: Build and push image
if: github.event.inputs.target == ‘acr’ || github.event.inputs.target == ‘all’
      uses: docker/build-push-action@v4
      with:
        context: app
        file: app/Dockerfile
        push: true
        tags: |
          ${{ github.event.inputs.environment }}azurecontainerregistry.azurecr.io/app-image:latest
    - name: Ensure Infra RG Exists
      if: github.event.inputs.target == ‘infra’ || github.event.inputs.target == ‘all’
      run: |
        RG_EXISTS=$(az group exists --name ${{ github.event.inputs.environment }}-infra-rg)
        if [ "$RG_EXISTS" = true ]; then
          echo "Resource group exists."
        else
          echo "Resource group does not exist. Creating …"
        az group create \
          --name ${{ github.event.inputs.environment }}-infra-rg \
          --location ‘swedencentral’
          echo "Resource group ${{ github.event.inputs.environment }}-infra-rg created."
        fi
    - name: Bicep Deploy
      if: github.event.inputs.target == ‘infra’ || github.event.inputs.target == ‘all’
      uses: Azure/bicep-deploy@v2.1.0
      with:
        name: infra-deployment
        type: deployment
        operation: create
        scope: resourceGroup
        subscription-id: ${{ secrets.AZURE_SUBSCRIPTION }}
        resource-group-name: ${{ github.event.inputs.environment }}-infra-rg
        template-file: infra/main.bicep
        parameters-file: infra/parameters/${{ github.event.inputs.environment }}.bicepparam
        parameters: >
          {
            "postgresAdminPassword":"${{ secrets.PG_PASSWORD }}",
            "postgresAdminUser":"${{ secrets.PG_USER }}"
          }

Appendix I. GitHub Actions Workflow for Infrastructure Teardown

The delete-infra.yml workflow facilitates safe deletion of Azure infrastructure, including cleanup of role assignments and removal of resource groups. It supports selective deletion by environment and target scope (infra, ACR, or both).
name: Delete Azure Resources
on:
  workflow_dispatch:
    inputs:
      environment:
        description: ‘Target environment’
        required: true
        default: ‘dev’
        type: choice
        options:
            - dev
            - qa
            - prod
      target:
        description: ‘RG to delete’
        required: true
        default: ‘all’
        type: choice
        options:
          - infra
          - acr
          - all

jobs:
  Delete-Resources:
    runs-on: ubuntu-latest
    environment: ${{ github.event.inputs.environment }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Azure Login
        uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
      - name: Delete Infra Resource Group
        if: github.event.inputs.target == ‘infra’ || github.event.inputs.target == ‘all’
        run: |
          echo "Checking for Infra Resource Group: ${{ github.event.inputs.environment }}-infra-rg"
          INFRA_RG_EXISTS=$(az group exists --resource-group ${{ github.event.inputs.environment }}-infra-rg)
          if [ "$INFRA_RG_EXISTS" = true ]; then
              OBJECT_ID=$(az identity show --name "ContAppManIdentity-${{ github.event.inputs.environment }}" --resource-group "${{ github.event.inputs.environment }}-infra-rg" --query ‘principalId’ -o tsv)
              echo "Managed Identity found: $OBJECT_ID. Delete all role assignments."
              az role assignment delete --assignee "$OBJECT_ID" --scope /subscriptions/${{ secrets.AZURE_SUBSCRIPTION }}
              echo "Roles have been removed for Managed Identity"
              echo "Infra resource group exists. Deleting..."
              az group delete --resource-group "${{ github.event.inputs.environment }}-infra-rg" --yes
              echo "Infra resource group deleted."
          else
              echo "Infra resource group does not exist."
          fi
      - name: Delete ACR Resource Group
        if: github.event.inputs.target == ‘acr’ || github.event.inputs.target == ‘all’
        run: |
          echo "Checking for ACR Resource Group: ${{ github.event.inputs.environment }}-acr-rg"
          RG_EXISTS=$(az group exists --resource-group ${{ github.event.inputs.environment }}-acr-rg)
          if [ "$RG_EXISTS" = true ]; then
            echo "ACR resource group exists. Deleting..."
            az group delete --resource-group "${{ github.event.inputs.environment }}-acr-rg" --yes
            echo "ACR resource group deleted."
          else
            echo "ACR resource group does not exist."
          fi

References

  1. Pipinellis, A. GitHub Essentials: Unleash the Power of Collaborative Development; Packt Publishing: Birmingham, UK, 2018. [Google Scholar]
  2. Soni, M. Mastering GitHub Actions: Automate Your Workflow with CI/CD; Packt Publishing: Birmingham, UK, 2021. [Google Scholar]
  3. Zaal, S. Azure DevOps Explained; Packt Publishing: Birmingham, UK, 2021. [Google Scholar]
  4. Westby, E.J.H. Git for Teams: A User-Centered Approach to Creating Efficient Workflows in Git; O’Reilly Media: Sebastopol, CA, USA, 2015. [Google Scholar]
  5. Loeliger, J.; McCullough, M. Version Control with Git: Powerful Tools and Techniques for Collaborative Software Development; O’Reilly Media: Sebastopol, CA, USA, 2012. [Google Scholar]
  6. Laster, B. Learning GitHub Actions: Automation and Integration of CI/CD with GitHub; O’Reilly Media: Sebastopol, CA, USA, 2023. [Google Scholar]
  7. Silverman, R.E. Git Pocket Guide: A Working Introduction; O’Reilly Media: Sebastopol, CA, USA, 2013. [Google Scholar]
  8. Reddington, C. GitHub Actions in Action; Manning: Shelter Island, NY, USA, 2022. [Google Scholar]
  9. Forsgren, N.; Humble, J.; Kim, G. Accelerate: The Science of Lean Software and DevOps; IT Revolution Press: Portland, OR, USA, 2018. [Google Scholar]
  10. Zaal, S. Azure DevOps: A Complete Guide to CI/CD Pipelines; Packt Publishing: Birmingham, UK, 2022. [Google Scholar]
  11. Kim, G.; Humble, J.; Debois, P.; Willis, J. The DevOps Handbook: How to Create World-Class Agility, Reliability, and Security in Technology Organizations; IT Revolution Press: Portland, OR, USA, 2021. [Google Scholar]
  12. Humble, J.; Farley, D. Continuous Delivery: Reliable Software Releases Through Build, Test, and Deployment Automation; Addison-Wesley: Boston, MA, USA, 2010. [Google Scholar]
  13. Davis, J.; Daniels, R. Effective DevOps: Building a Culture of Collaboration, Affinity, and Tooling at Scale; O’Reilly Media: Sebastopol, CA, USA, 2016. [Google Scholar]
  14. Chacon, S.; Straub, B. Pro Git; Apress: New York, NY, USA, 2014. [Google Scholar]
  15. Morris, K. Infrastructure as Code: Managing Servers in the Cloud; O’Reilly Media: Sebastopol, CA, USA, 2016. [Google Scholar]
  16. Duvall, P.M.; Matyas, S.; Glover, A. Continuous Integration: Improving Software Quality and Reducing Risk; Addison-Wesley: Boston, MA, USA, 2007. [Google Scholar]
  17. Soni, M. DevOps with Azure: Implementing DevOps Using Microsoft Azure; Apress: New York, NY, USA, 2020. [Google Scholar]
  18. Humble, J.; Molesky, J.; O’Reilly, B. Lean Enterprise: How High-Performance Organizations Innovate at Scale; O’Reilly Media: Sebastopol, CA, USA, 2015. [Google Scholar]
  19. Price, M.J. Azure DevOps for Beginners: A Step-by-Step Guide to CI/CD Pipelines; Packt Publishing: Birmingham, UK, 2022. [Google Scholar]
  20. Moyle, E.; Kelley, D. Practical Cybersecurity Architecture—Second Edition: A Guide to Creating and Implementing Robust Designs for Cybersecurity Architects; Packt Publishing: Birmingham, UK, 2023. [Google Scholar]
  21. Hüttermann, M. DevOps for Developers; Apress: New York, NY, USA, 2012. [Google Scholar]
  22. Newman, S. Building Microservices: Designing Fine-Grained Systems, 2nd ed.; O’Reilly Media: Sebastopol, CA, USA, 2021. [Google Scholar]
  23. Sinha, C. Mastering Azure DevOps: A Comprehensive Guide to Implementing CI/CD Pipelines; Apress: New York, NY, USA, 2021. [Google Scholar]
  24. Arundel, J.; Domingus, J. Cloud Native DevOps with Kubernetes: Building, Deploying, and Scaling Modern Applications in the Cloud, 2nd ed.; O’Reilly Media: Sebastopol, CA, USA, 2022. [Google Scholar]
  25. Farcic, V.; Pope, D. DevOps Toolkit Series; Leanpub: Victoria, BC, Canada, 2020. [Google Scholar]
  26. Mitesh, S. Hands-On Azure DevOps: Implementing CI/CD Pipelines; Apress: New York, NY, USA, 2021. [Google Scholar]
  27. Leszko, R. Continuous Delivery with Docker and Jenkins: Create Secure Applications by Building Complete CI/CD Pipelines, 2nd ed.; Packt Publishing: Birmingham, UK, 2019. [Google Scholar]
  28. Limoncelli, T.; Chalup, S.; Hogan, C. The Practice of Cloud System Administration: DevOps and SRE Practices for Web Services; Addison-Wesley: Boston, MA, USA, 2021. [Google Scholar]
  29. Cain, R. Azure Infrastructure as Code Using Bicep; Apress: New York, NY, USA, 2023. [Google Scholar]
  30. Laster, B. GitHub Actions: The Complete Guide; O’Reilly Media: Sebastopol, CA, USA, 2024. [Google Scholar]
  31. Been, H. Infrastructure as Code on Azure with Bicep: Automating Resource Deployment; Manning Publications: Shelter Island, NY, USA, 2023. [Google Scholar]
  32. Soni, M. GitHub Actions for DevOps Engineers; Packt Publishing: Birmingham, UK, 2023. [Google Scholar]
  33. Laster, B. Professional Git; Wrox: Hoboken, NJ, USA, 2016. [Google Scholar]
  34. Krief, M. Learning DevOps: A Comprehensive Guide to Accelerating DevOps Culture Adoption with Terraform, Azure DevOps, Kubernetes, and Jenkins, 2nd ed.; Packt Publishing: Birmingham, UK, 2022. [Google Scholar]
  35. Machiraju, S.; Gaurav, S. Azure Automation Using the ARM Template and Bicep; Springer: Berlin/Heidelberg, Germany, 2023. [Google Scholar]
Figure 1. GitHub repository structure.
Figure 1. GitHub repository structure.
Futureinternet 17 00359 g001
Figure 2. High-level solution architecture for automated Azure deployment using Bicep and GitHub Actions.
Figure 2. High-level solution architecture for automated Azure deployment using Bicep and GitHub Actions.
Futureinternet 17 00359 g002
Figure 3. Parameter files for all environments.
Figure 3. Parameter files for all environments.
Futureinternet 17 00359 g003
Figure 4. Deployment pipeline steps in the GitHub portal.
Figure 4. Deployment pipeline steps in the GitHub portal.
Futureinternet 17 00359 g004
Figure 5. Deletion pipeline steps in the GitHub portal.
Figure 5. Deletion pipeline steps in the GitHub portal.
Futureinternet 17 00359 g005
Table 1. Comparative overview of key characteristics of infrastructure-as-code tools for cloud provisioning.
Table 1. Comparative overview of key characteristics of infrastructure-as-code tools for cloud provisioning.
Feature/ToolBicepTerraformPulumiAWS CloudFormation
TypeDeclarativeDeclarative (HCL)Imperative/Declarative (via code)Declarative
Cloud Provider SupportAzure-onlyMulti-cloud (Azure, AWS, GCP)Multi-cloudAWS-only
Language/SyntaxDomain-specific Bicep languageHashiCorp Configuration Language (HCL)General-purpose languages (Python, TypeScript)JSON or YAML
Ease of UseHigh (simple syntax, modularity)Moderate (requires HCL familiarity)Depends on programming experienceModerate to low (verbose, complex for large deployments)
Integration with AzureNative support; rapid feature updatesSlower adoption of new Azure featuresDepends on provider APIsN/A
Integration with AWSNoneStrongStrongNative
Modularity andReusabilityStrong support for modulesStrong module ecosystemHigh (via programming constructs and libraries)Moderate (nested stacks supported)
State ManagementHandled by Azure Resource ManagerRequires backend configuration Abstracted or optionalManaged internally
Learning CurveLow (especially for Azure teams)ModerateHigher (for non-developers)Moderate to high
Complex Logic SupportLimitedLimitedStrong (due to the use of full programming languages)Limited
Feature Gaps/LimitationsAzure-only; no multi-cloudPotential delays in support for new Azure featuresRuntime environment required; complexity in orchestrationVerbose; complex YAML/JSON syntax
Ideal Use CaseAzure-centric deploymentsMulti-cloud or hybrid cloud strategiesDeveloper-focused teams building reusable componentsAWS-centric, large-scale infrastructure
Table 2. Prioritization of deployment goals based on importance for CI/CD infrastructure.
Table 2. Prioritization of deployment goals based on importance for CI/CD infrastructure.
GoalDescriptionWeight (1–5)Rationale
SecurityProtection of credentials, access control, private networking5Critical for compliance and trust in production systems
ConsistencyEnsuring identical deployments across environments5Foundation for reproducibility and environment parity
AutomationFully automated deployment and teardown workflows5Enables CI/CD and reduces human error
MaintainabilityModular structure, easy updates and reviews4Important for long-term evolution and code quality
TraceabilityGit-based version control, history, rollback capabilities4Enhances auditability and debugging
ReusabilityParametrized modules applicable across projects3Useful but secondary to security and consistency
CollaborationShared ownership across development and operations3Culturally important but harder to measure technically
Cost ControlRight-sizing, ephemeral environments, teardown automation3Practical but dependent on business policies
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.

Share and Cite

MDPI and ACS Style

Manolov, V.; Gotseva, D.; Hinov, N. Creating Automated Microsoft Bicep Application Infrastructure from GitHub in the Azure Cloud. Future Internet 2025, 17, 359. https://doi.org/10.3390/fi17080359

AMA Style

Manolov V, Gotseva D, Hinov N. Creating Automated Microsoft Bicep Application Infrastructure from GitHub in the Azure Cloud. Future Internet. 2025; 17(8):359. https://doi.org/10.3390/fi17080359

Chicago/Turabian Style

Manolov, Vladislav, Daniela Gotseva, and Nikolay Hinov. 2025. "Creating Automated Microsoft Bicep Application Infrastructure from GitHub in the Azure Cloud" Future Internet 17, no. 8: 359. https://doi.org/10.3390/fi17080359

APA Style

Manolov, V., Gotseva, D., & Hinov, N. (2025). Creating Automated Microsoft Bicep Application Infrastructure from GitHub in the Azure Cloud. Future Internet, 17(8), 359. https://doi.org/10.3390/fi17080359

Note that from the first issue of 2016, this journal uses article numbers instead of page numbers. See further details here.

Article Metrics

Back to TopTop