Dukungan SDK klien Azure IoT untuk server token pihak ketiga

Azure IoT
Azure IoT Hub

Artikel Mengontrol akses ke IoT Hub menggambarkan bagaimana layanan token pihak ketiga dapat diintegrasikan dengan IoT Hub. Artikel ini menggambarkan dukungan untuk autentikasi token tanda tangan akses berbagi (SAS) di setiap klien SDK Azure IoT. Ini juga menguraikan apa yang perlu diimplementasikan dalam aplikasi perangkat menggunakan SDK yang sesuai untuk setiap bahasa, dan cara menggunakan token cakupan perangkat atau modul untuk kebijakan akses bersama DeviceConnect atau ModuleConnect.

Konteks dan masalah

Dokumentasi keamanan Azure IoT Hub saat ini membahas pola server token pihak ketiga untuk autentikasi SAS dengan Perangkat IoT Hub by IoT menggunakan SDK klien Azure IoT. Namun, asumsi yang salah yang dibuat oleh pelanggan selama keterlibatan perusahaan baru-baru ini menunjukkan bahwa tanpa klarifikasi lebih lanjut, Anda dapat mengembangkan kesan yang menyesatkan tentang tingkat dukungan yang diterapkan secara default di SDK klien Azure IoT.

Artikel ini membahas pembelajaran dari keterlibatan tersebut dan mengklarifikasi apa yang perlu dilakukan di setiap SDK untuk perangkat guna mencapai autentikasi server token pihak ketiga. Artikel ini juga harus mencegah Anda membuat asumsi salah yang serupa tentang dukungan untuk pola server token pihak ketiga di SDK klien Azure IoT.

Solution

SDK klien Azure IoT menyediakan berbagai tingkat dukungan untuk otentikasi token SAS, masing-masing memerlukan beberapa kode khusus untuk menyelesaikan fungsi autentikasi dan manajemen token.

Frekuensi evaluasi token tergantung pada protokol transportasi yang dipilih — MQTT, AMQP, atau HTTPS. Variasi tergantung pada kemampuan protokol untuk mendukung pembaruan token proaktif dan time-out sesi. Hanya AMQP yang menerapkan dukungan pembaruan proaktif. Ini berarti transportasi lain akan menutup koneksi pada kegagalan autentikasi token SAS, dan kemudian perlu melakukan operasi koneksi baru. Ini adalah operasi konektivitas yang berpotensi mahal bagi klien.

Jika autentikasi SAS gagal, kesalahan akan dinaikkan oleh implementasi transportasi yang dapat ditangani dalam aplikasi perangkat oleh penanganan aktivitas "Status Koneksi Diubah". Kegagalan untuk menerapkan penanganan seperti itu biasanya akan membuat aplikasi perangkat berhenti karena kesalahan. Dengan implementasi penanganan aktivitas dan fungsi pembaruan token yang benar, transportasi dapat mencoba kembali koneksi.

Ilustrasi berikut menggambarkan pola server token pihak ketiga:

Illustration of the third-party token-server pattern

Gambar berikut menggambarkan dukungan implementasi di SDK klien Azure IoT dengan integrasi Operator Mobile Net:

Flowchart of implementation support in the Azure IoT client SDK with Mobile Net Operator integration

Implementasi sampel disertakan dalam repositori Azure Samples di GitHub.

Masalah dan pertimbangan

Pertimbangkan poin-poin berikut saat memutuskan apakah akan menerapkan pola ini:

  • SDK klien Azure IoT Hub Device Provisioning Service (Azure DPS) tidak mendukung autentikasi token SAS. REST API Azure DPStidak mendukung autentikasi token SAS. Oleh karena itu, untuk menggunakan Azure DPS dengan layanan token pihak ketiga untuk autentikasi SAS, aplikasi perangkat harus menerapkan proses DPS perangkat menggunakan REST API Azure DPS.

  • Ini terdiri dari membuat operasi permintaan pendaftaran awal, dan kemudian pemungutan suara API status operasional sampai proses DPS berhasil atau gagal. Saat berhasil, detail penyediaan perangkat dapat diperoleh dengan memintanya dari Pendaftaran Runtime REST API Azure DPS.

Referensi:

Kapan menggunakan pola ini

Anda harus menggunakan pola ini kapan pun Anda ingin mengautentikasi ke Azure IoT Hub dari perangkat IoT menggunakan berbagai SDK Klien Azure IoT. Alih-alih menggunakan SDK klien untuk autentikasi token SAS, gunakan API REST Azure DPS untuk memastikan penerapan dukungan perpanjangan proaktif untuk semua mekanisme transportasi.

Contoh

Bagian berikut menawarkan contoh yang dapat Anda gunakan untuk berbagai bahasa pemrograman, seperti Embedded C, .NET, Java, dan Python.

Perangkat SDK Azure IoT Hub untuk C dan perangkat SDK Azure IoT Hub untuk Embedded C

Pendekatan berikut dapat digunakan dalam aplikasi perangkat yang dibangun menggunakan SDK Azure IoT C atau SDK Azure IoT Embedded C. SDK tidak menyediakan manajemen seumur hidup token SAS, oleh karena itu Anda harus menerapkan kemampuan manajer seumur hidup token SAS.

Token SAS dapat digunakan melalui struktur IOTHUB_CLIENT_CONFIG dengan mengatur anggota deviceSasToken ke token dan membuat null deviceKey. Nilai lain yang tidak digunakan, seperti protocolGatewayHostName, juga harus diatur ke null.

IOTHUB_CLIENT_CONFIG* CONFIG = (IOTHUB_CLIENT_CONFIG*)malloc(sizeof(IOTHUB_CLIENT_CONFIG));

CONFIG->PROTOCOL = PROTOCOL;
CONFIG->DEVICEID = DEVICEID;
CONFIG->IOTHUBNAME = IOTHUBNAME;
CONFIG->IOTHUBSUFFIX = IOTHUBSUFFIX;
CONFIG->DEVICEKEY = 0;
CONFIG->DEVICESASTOKEN = TOKEN;
CONFIG->PROTOCOLGATEWAYHOSTNAME = 0;

// The created IOTHUB_CLIENT_CONFIG can then be provided to the IoTHubDeviceClient_Create function to establish a DeviceClient instance.
if ((IOTHUBCLIENTHANDLE = IoTHubDeviceClient_Create(CONFIG)) == NULL) {
    (void)printf("ERROR: IOTHUBCLIENTHANDLE IS NULL!\r\n");
}

// To capture SAS token authentication failures, a handler needs to be implemented for the IoTHubDeviceClient_SetConnectionStatusCallback.
(void)IoTHubDeviceClient_SetConnectionStatusCallback(IOTHUBCLIENTHANDLE, CONNECTION_STATUS_CALLBACK, NULL);

Connection_status_callback dapat menangkap IOTHUB_CLIENT_CONNECTION_STATUS_REASON dari IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN untuk memicu pembaruan token SAS melalui layanan token pihak ketiga. Ini diperlukan untuk semua transportasi untuk menangkap masalah koneksi tetapi secara khusus diperlukan oleh transportasi yang tidak mendukung pembaruan token SAS proaktif. Manajemen seumur hidup token SAS proaktif dapat diimplementasikan sebagai fungsi yang berulang kali dijalankan selama aplikasi perangkat loop "operasional". Memastikan masa pakai token sering dievaluasi, dan pembaruan token dapat dieksekusi secara proaktif bila diperlukan.

Ringkasan implementasi autentikasi token SAS untuk SDK C:

  1. Menerapkan handler ConnectionStatusCallback untuk menangkap peristiwa IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN dan memicu pembaruan token.

  2. Gunakan IOTHUB_CLIENT_CONFIG untuk menyediakan token SAS perangkat untuk IoTHubDeviceClient_Create.

  3. Menerapkan manajemen seumur hidup token SAS proaktif sebagai bagian dari loop operasi aplikasi perangkat.

SDK perangkat Azure IoT Hub untuk .NET

SDK klien Azure IoT untuk .NET menerapkan dukungan untuk manajemen masa pakai token SAS melalui kelas DeviceAuthenticationWithTokenRefresh abstrak. Implementasi konkret dari kelas ini, menambahkan fungsionalitas pembaruan token, dapat disediakan sebagai metode autentikasi ke metode DeviceClient.Create. Implementasi transportasi akan secara otomatis memperbarui token melalui metode autentikasi sesuai kebutuhan. ConnectionStatusChangesHandler diperlukan untuk menangkap perubahan koneksi dan mencegah pengecualian dinaikkan oleh transportasi.

Contoh implementasi berdasarkan kelas DeviceAuthenticationWithTokenRefreash:

internal class StsDeviceAuthenticationWithTokenRefresh : DeviceAuthenticationWithTokenRefresh
{

    private readonly string _stsConnectUrl = "http://localhost:8080/sts/azure/token/operations?sr={0}/devices/{1}";

    private const int DEFAULTTIMETOLIVESECONDS = 1 * 60 * 60;

    private const int DEFAULTBUFFERPERCENTAGE = 15;

    public StsDeviceAuthenticationWithTokenRefresh(string deviceId, int suggestedTimeToLiveSeconds, int timeBufferPercentage) : BASE(deviceId, suggestedTimeToLiveSeconds, timeBufferPercentage)
    {
        If(String.IsNullOrWhitespace(deviceId)){
            throw new ArgumentNullException(nameof(deviceId));
        }
    }

    protected override async Task<string> SafeCreateNewToken(string iotHub, int suggestedTimeToLive)
    {
        string result;
        string url = string.Format(_stsConnectUrl, iotHub, deviceId);

        using (HttpClientHandler handler = new HttpClientHandler())
        using (HttpClient client = new HttpClient(handler))
        {
            try
            {
                HttpResponseMessage response = await client.GetAsync(url);
                if (response.IsSuccessStatusCode)
                {
                    result = await response.Content.ReadAsStringAsync();
                }
                else
                {
                    throw new HttpRequestException($"Request failed with status code {response.StatusCode}.");
                }
            }
            catch (HttpRequestException)
            {
                result = null;
            }
        }

        return result;
    }
}

Ringkasan implementasi autentikasi token SAS untuk SDK perangkat Azure IoT Hub untuk .NET:

  1. Menerapkan kelas konkret berdasarkan kelas abstrak DeviceAuthenticationWithTokenRefresh, yang menerapkan fungsionalitas pembaruan token.

  2. Menerapkan ConnectionStatusChangesHandler untuk menangkap status koneksi transportasi dan menghindari pengecualian yang diajukan oleh implementasi transportasi.

Referensi:

Perangkat SDK Azure IoT Hub untuk Java

SDK Klien Azure IoT untuk Java menerapkan dukungan untuk manajemen seumur hidup token SAS melalui Antarmuka SasTokenProvider. Kelas yang mengimplementasikan antarmuka ini dengan fungsi pembaruan token SAS dapat digunakan sebagai SecurityProvider di konstruktor DeviceClient. Implementasi transportasi akan secara otomatis memperbarui token melalui penyedia keamanan sesuai kebutuhan. ConnectionStatusChangeCallback perlu didaftarkan untuk menangkap perubahan koneksi dan mencegah pengecualian dinaikkan oleh transportasi.

Contoh implementasi penyedia keamanan yang menerapkan antarmuka SasTokenProvider:

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class StsSecurityProvider implements SasTokenProvider {
    private final String hostname;
    private final String deviceId;
    private int renewalBufferSeconds;
    private long expiryTimeSeconds;
    private char[] sasToken;

    public StsSecurityProvider(String hostname, String deviceId) {
        this.hostname = hostname;
        this.deviceId = deviceId;
        this.renewalBufferSeconds = 120;
        this.expiryTimeSeconds = (System.currentTimeMillis() / 1000);
    }

    @Override
    public char[] getSasToken() {
        long currentTimeSeconds = (System.currentTimeMillis() / 1000);
        try {
            if (this.sasToken == null || this.expiryTimeSeconds + this.renewalBufferSeconds >= currentTimeSeconds) {
                this.sasToken = stsGetToken();
                assert this.sasToken != null;
                String t = String.copyValueOf(this.sasToken);
                String[] bits = t.split("SE=");
                long l = Long.parseLong(bits[1]);
                this.expiryTimeSeconds = l; // the SE= number
                this.renewalBufferSeconds = (int)(l * 0.15); // renew within 15% of expiry
            }
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
        return this.sasToken;
    }

    private char[] stsGetToken() throws IOException, InterruptedException {
        String stsUrl = String.format("http://localhost:8080/sts/azure/token/operations?sr=%s/devices/%s", this.hostname, this.deviceId);
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(stsUrl))
            .timeout(Duration.ofMinutes(2))
            .header("Content-Type", "application/json")
            .build();
        HttpClient client = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .connectTimeout(Duration.ofSeconds(20))
            .build();
        HttpResponse < String > response = client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() < 200 || response.statusCode() >= 300) {
            return null;
        }
        if (response.body().isEmpty()) {
            return null;
        }
        return response.body().toCharArray();
    }
}

Ringkasan implementasi autentikasi token SAS untuk SDK perangkat Azure IoT Hub untuk Java:

  1. Menerapkan antarmuka SasTokenProvider pada kelas dan menyertakan fungsionalitas pembaruan token.

  2. Menerapkan ConnectionStatusChangeCallback untuk menangkap perubahan status koneksi transportasi dan menghindari pengecualian yang diajukan oleh implementasi transportasi.

Referensi:

Perangkat SDK Azure IoT Hub untuk Phyton

SDK perangkat Azure IoT Hub untuk Python mengimplementasikan dukungan token SAS melalui metode pada objek IoTHubDeviceClient. Metode ini memungkinkan pembuatan klien perangkat menggunakan token, dan kemampuan untuk menyediakan token yang diperbarui setelah klien perangkat dibuat. Mereka tidak menerapkan manajemen token seumur hidup, tetapi ini dapat diimplementasikan dengan mudah sebagai operasi asinkron.

Implementasi contoh Python 3.7 hanya menampilkan garis besar fungsionalitas:

import asyncio
import iothub_device_client

async def main():
    # Get a SAS token you generated
    sastoken = get_new_sastoken()
    # The client object is used to interact with your Azure IoT Hub.
    device_client = iothub_device_client.create_from_sastoken(sastoken)

    # Connect the client
    await device_client.connect()

    # Define behavior for providing new SAS tokens to prevent expiry
    async def sastoken_keepalive():
        while True:
            await asyncio.sleep(new_token_interval)
            sastoken = get_new_sastoken()
            await device_client.update_sastoken(sastoken)

    # Also run the SAS token keepalive in the event loop
    keepalive_task = asyncio.create_task(sastoken_keepalive())

    # Cancel the SAS token update task
    keepalive_task.cancel()

    # Finally, shut down the client
    await device_client.shutdown()

if __name__ == "main":
    asyncio.run(main())

Ringkasan SDK perangkat Azure IoT Hub untuk autentikasi token Python SAS:

  1. Buat fungsi pembuatan token SAS.

  2. Buat klien perangkat menggunakan IoTHubDeviceClient.create_from_sastoken.

  3. Kelola masa pakai token sebagai aktivitas terpisah, berikan klien perangkat token baru bila diperlukan dengan metode IoTHubDeviceClient.update_sastoken.

Referensi:

SDK Perangkat Azure IoT Hub untuk Node.JS/JavaScript

Azure IoT untuk Node.JS/JavaScript mengimplementasikan SharedAccessSignatureAuthenticationProvider yang akan melayani token SAS ke klien perangkat dan mengangkut untuk diautentikasi dengan Azure IoT Hub. Ini tidak menerapkan fungsi pembaruan token apa pun. Aplikasi perangkat harus mengelola token seumur hidup, memperbarui token sesuai kebutuhan.

Gunakan metode klien perangkat dariSharedAccessSignature dan updateSharedAccessSignature untuk memulai koneksi dengan Azure IoT Hub dan memberikan token baru ke SharedAccessSignatuteAuthenticationProvider, yang akan menyebabkan penyedia autentikasi memancarkan peristiwa newTokenAvailable ke transportasi.

Sampel token SAS dasar disediakan dalam contoh simple_sample_device_with_sas.js example.

Ringkasan SDK perangkat Azure IoT Hub untuk Node.JS/JavaScript:

  1. Menerapkan manajemen dan pembaruan seumur hidup token SAS.

  2. Menggunakan klien perangkat dariSharedAccessSignature untuk membuat instans klien perangkat.

  3. Menggunakan klien perangkat updateSharedAccessSignature untuk menyediakan token yang diperbarui.

Referensi:

Langkah berikutnya