Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions mi-azuresql-spring/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Azure SQL with Managed Identity - Spring Boot Demo

This project demonstrates how to connect to Azure SQL Database using Azure Managed Identity in a Spring Boot application.

## Features

- Spring Boot application with Azure SQL Database connectivity
- Azure Managed Identity authentication (no passwords required)
- REST API endpoints for testing database connectivity
- Proper Spring Cloud Azure integration

## Configuration

The application is configured to use Azure Managed Identity for authentication with Azure SQL Database.

### Required Environment Variables

- `AZ_DATABASE_SERVER_NAME`: Your Azure SQL Server name (without .database.windows.net)
- `AZURE_CLIENT_ID`: The client ID of your User-Assigned Managed Identity

### Application Properties

The `application.properties` file contains:

```properties
# Azure SQL Database Configuration with Managed Identity
spring.datasource.url=jdbc:sqlserver://${AZ_DATABASE_SERVER_NAME}.database.windows.net:1433;database=demo;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryMSI

# Enable Azure managed identity for Spring Cloud Azure
spring.cloud.azure.credential.managed-identity-enabled=true
spring.cloud.azure.credential.client-id=${AZURE_CLIENT_ID}
```

## Dependencies

Key dependencies used in this project:

- `spring-boot-starter-web`: Web layer and REST controllers
- `spring-boot-starter-jdbc`: JDBC support
- `spring-cloud-azure-starter`: Azure integration for Spring Boot
- `mssql-jdbc`: Microsoft SQL Server JDBC driver

## API Endpoints

Once running, the application exposes the following endpoints:

- `GET /api/database/health`: Check if the application is running
- `GET /api/database/test-connection`: Test database connectivity
- `GET /api/database/version`: Get database version information
- `GET /api/database/test-query`: Execute a simple test query

## Building and Running

```bash
# Build the project
mvn clean compile

# Run the application (requires Azure environment with configured managed identity)
mvn spring-boot:run
```

## Prerequisites

1. Azure SQL Database instance
2. User-Assigned Managed Identity configured in Azure
3. Proper access permissions granted to the managed identity on the SQL database
4. Application running in an Azure environment that supports managed identity (e.g., Azure App Service, Azure VM, Azure Container Instances)

## Azure Setup

1. Create an Azure SQL Database
2. Create a User-Assigned Managed Identity
3. Grant the managed identity access to the SQL database
4. Configure the application environment variables
5. Deploy to an Azure service that supports managed identity

For more information about setting up managed identity with Azure SQL, refer to the [Azure documentation](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview).
93 changes: 93 additions & 0 deletions mi-azuresql-spring/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>mi-azuresql-spring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>mi-azuresql-spring</name>
<description>Azure SQL with Managed Identity Spring Boot Demo</description>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<java.version>17</java.version>
<spring.boot.version>3.1.0</spring.boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<!-- Spring Boot BOM -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/>
</parent>

<!-- Add Spring Cloud Azure BOM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>5.22.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Boot Starter JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!-- SQL Server JDBC Driver -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>12.4.2.jre11</version>
</dependency>

<!-- Add Spring Cloud Azure starter for managed identity support -->
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter</artifactId>
</dependency>

<!-- H2 Database for testing -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>

<!-- Spring Boot Test Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.azuresql;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AzureSqlManagedIdentityApplication {

public static void main(String[] args) {
SpringApplication.run(AzureSqlManagedIdentityApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.example.azuresql.controller;

import com.example.azuresql.service.DatabaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/database")
public class DatabaseController {

@Autowired
private DatabaseService databaseService;

@GetMapping("/test-connection")
public String testConnection() {
return databaseService.testConnection();
}

@GetMapping("/version")
public String getDatabaseVersion() {
return databaseService.getDatabaseVersion();
}

@GetMapping("/test-query")
public String testQuery() {
return databaseService.testQuery();
}

@GetMapping("/health")
public String health() {
return "Azure SQL Managed Identity Spring application is running!";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.example.azuresql.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@Service
public class DatabaseService {

@Autowired
private DataSource dataSource;

@Autowired
private JdbcTemplate jdbcTemplate;

/**
* Test database connection using Azure Managed Identity
*/
public String testConnection() {
try (Connection connection = dataSource.getConnection()) {
return "Successfully connected to Azure SQL Database using Managed Identity!";
} catch (SQLException e) {
return "Failed to connect to database: " + e.getMessage();
}
}

/**
* Get database version using JdbcTemplate
*/
public String getDatabaseVersion() {
try {
return jdbcTemplate.queryForObject("SELECT @@VERSION", String.class);
} catch (Exception e) {
return "Failed to get database version: " + e.getMessage();
}
}

/**
* Test a simple query to validate the connection
*/
public String testQuery() {
try {
String result = jdbcTemplate.queryForObject("SELECT 'Hello from Azure SQL!' as message", String.class);
return result;
} catch (Exception e) {
return "Failed to execute test query: " + e.getMessage();
}
}
}
17 changes: 17 additions & 0 deletions mi-azuresql-spring/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Azure SQL Database Configuration with Managed Identity
spring.datasource.url=jdbc:sqlserver://${AZ_DATABASE_SERVER_NAME}.database.windows.net:1433;database=demo;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryMSI

# Enable Azure managed identity for Spring Cloud Azure
spring.cloud.azure.credential.managed-identity-enabled=true
spring.cloud.azure.credential.client-id=${AZURE_CLIENT_ID}

# Application Configuration
server.port=8080
logging.level.com.example=DEBUG
logging.level.com.microsoft.sqlserver=DEBUG

# Database server name placeholder
AZ_DATABASE_SERVER_NAME=<your-database-server-name>

# Managed identity client ID placeholder
AZURE_CLIENT_ID=<your-managed-identity-client-id>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.azuresql;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;

@SpringBootTest
@TestPropertySource(properties = {
"AZ_DATABASE_SERVER_NAME=test-server",
"AZURE_CLIENT_ID=test-client-id",
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.cloud.azure.credential.managed-identity-enabled=false"
})
class AzureSqlManagedIdentityApplicationTests {

@Test
void contextLoads() {
// This test ensures the application context loads successfully
// with mocked properties to avoid actual Azure SQL connection
}
}