# การป้องกันความลับหลุดตอนที่ 3

## 😘 ทวนปัญหา

จาก 2 บทความที่ผ่านมาเราก็จะเห็นวิธีการเก็บ **`ความลับ`** ของแอพเราอย่างง่ายๆไปละ แถมยังสามารถจัดการแยก **`Development Environment`** ออกจาก **`Production Environment`** ได้ด้วย แต่ว่ามันก็ยังไม่สามารถเก็บความลับได้ถึงขีดสุด ดังนั้นเรามาไล่รายการที่ค้างกันก่อนดีก่า ตามด้านล่างเบย

### 💔 รายการที่ต้องแก้

* ~~การผัง Secret ไว้เป็น Hard code ทำให้เราต้อง Build & Deploy โปรเจคใหม่เท่านั้น~~
* ~~ใน Source code ของมี Secret ติดเข้าไปใน commit เสมอ~~
* ~~ถ้าเราไม่ให้ access เข้าถึง service ตัวนั้นๆ เราก็จะเอาแอพขึ้นคลาว์ไม่ได้~~
* Developer บางคนอาจจะรู้ Secret ซึ่งเขาอาจจะเป็นคนร้ายในอนาคต หรือ เป็นจุดที่อันตรายถ้าเขาเก็บมันไว้ไม่ดี
* ถ้ามีคนที่มี access เข้าถึง service บนคลาว์ตัวนั้นๆได้ เขาก็สามารถเข้ามาดู secret เหล่านั้นได้เหมือนเดิม

{% hint style="success" %}
**แนะนำให้อ่าน**\
บทความนี้เป็นส่วนหนึ่งของคอร์ส [🤠 **Cloud Playground**](https://www.saladpuk.com/cloud/cloud-playground) ที่จะพาเพื่อนๆแมวน้ำทั้งหลายได้ลองมาดูว่า การสร้างโปรเจคเพื่อทำงานบนคลาว์ โดยใช้มาตรฐานสากลจริงๆแล้วเขาทำกันยังไง ส่วนถ้าสนใจอยากอ่านต่อก็กดไปที่ลิงค์สีฟ้าๆได้เลย

ส่วนถ้าอยากอ่านบทความก่อนหน้าให้อ่านได้จากลิงค์นี้เบย **\*\*\[**&#xE01;ารป้องกันความลับหลุดตอนที่ &#x32;**]\(**<https://www.saladpuk.com/cloud/cloud-playground/app-config-02>**) \*\***&#xE0B;ึ่งในบทนี้ผมอธิบายเรื่อง **Development Environment vs Production Environment** ไว้ในระดับนึงละ
{% endhint %}

ในตอนนี้ปัญหาของเราก็จะเหลือแค่ ป้องกันไม่ให้คนในทีมเป็นคนร้ายเสียเอง เนื่องจากบางคนอาจจะมีสิทธิ์ในการเข้าถึง `ความลับ` เหล่านั้นได้นั่นเอง

## 🤠 เก็บ Secret ด้วย App Configuration Service

คราวก่อนเรามีการเก็บความลับต่างๆไว้ภายใน **`Configuration`** ของตัว **Web App Service** ตามรูปด้านล่าง

![](/files/-Lwi72rQFB2LacUftEXe)

> ซึ่งการทำแบบนี้ก็ไม่ได้ผิดอะไรนะ เพียงแค่เราต้องไว้ใจ Developer คนที่สามารถเข้าถึง Web App Service ตัวนี้เป็นอย่างมากว่าเขาจะไม่แอบเข้ามาเอา `ความลับ` ที่เปิดโชว์อยู่ตรงนี้ไปทำมิตรดีมิตรร้ายอะไร (หุหุ)

สำหรับโปรเจคบางตัวที่มีระดับความซีเรียสของความลับสูงๆ เช่น การเงิน, ข้อมูลส่วนตัว บลาๆ มันก็อาจจะบังคับให้เราไม่สามารถทำในรูปแบบนี้ได้ ดังนั้นในรอบนี้เราจะ **แยกความลับออกจากคลาว์เซอร์วิส** เพื่อให้ความลับเรายิ่งเข้าถึงยากขึ้นไปอีก โดยในตัวอย่างนี้จะใช้วิธีแบบง่ายไปก่อนจะได้เข้าใจ concept พื้นฐานนั่นเอง ดังนั้นไปดูตัวช่วยในเรื่องนี้ของเรากันเลยดีกั่ว

### 🔥 สร้าง App Configuration Service

![](/files/-M-_UtoXkZ4P4ARVxQSM)

เจ้าตัวนี้จะช่วยให้เราบริหารจัดการ configuration ต่างๆของเราได้ง่ายขึ้น โดยที่เวลาเราจะแก้ configuration ต่างๆ เราก็ไม่จำเป็นต้อง rebuild & re-deploy ตัวแอพของเราเลย แถมยังเข้าถึงได้จากหลายๆแอพอีกด้วย ดังนั้นก็ทำการสร้างแล้วใส่ข้อมูลต่างๆตามชอบใจเลย

![เจ้าตัวนี้มี Free tier ให้เราใช้ได้นะ ไม่เสียกะตังเบย](/files/-LnPheSLr4nGC4TiFjpZ)

หลังจากที่สร้างมันเสร็จแล้ว เราก็จะไปดูที่เมนู `Configuration explorer` เพื่อเข้าไปจัดการเก็บความลับของเราไว้ในเจ้า service นี้กัน ตามรูปด้านล่างเรย

![](/files/-LnHRX0VIzEbihHWZ05C)

ซึ่งในเมนูนี้เขาจะโชว์รายการ configuration ทั้งหมดของเราขึ้นมา ซึ่งเจ้าตัวนี้ผมพึ่งสร้างขึ้นมามันก็เลยจะยังไม่มีรายการอะไรอยู่ในนี้ ดังนั้นเราก็จะลองสร้าง configuration ตัวแรกของเรากันดีกว่า โดยการกดปุ่ม **`+ Create`** ตามรูปด้านล่างเรยครัช

![ขอสร้างเป็น Key-value แบบธรรมดาไปก่อนนะ จะได้ไม่ งง](/files/-LsXDjy4oeJy2kk5fQ_J)

ถัดไปก็ทำการกำหนดค่าต่างๆ ซึ่งผมจะใช้ **Key** เดิมนั่นก็คือเจ้า **DbConnectionString** นั่นเอง ส่วนค่าของมันผมใช้เป็น Yeeha! from App Configuration ละกัน ส่วนที่เหลือจะใส่หรือไม่ใส่ก็ได้ แล้วก็กดกด **`Apply`** โลด

![](/files/-LoQRHaTLDmmdphmYWpw)

เสร็จเรียบร้อยละ เจ้า **DbConnectionStrign** ก็จะถูกเก็บเข้าไปอยู่ในตัว service ตัวนี้เรียบร้อยแล้ว

![](/files/-M1lg2XK9FBbt5twkJkb)

### 🔥 ทำ Web App ให้รองรับ App Configuration Service

เนื่องจากเราไม่อยากให้ความลับของเราไปโชว์หลาอยู่ที่ Web App Service ดังนั้นเราก็จะต้องมากำหนดให้เจ้าตัวเว็บของเราไปอ่านค่า configuration ต่างๆจาก App Configuration Service ที่เราพึ่งสร้างไปนั่นเอง ดังนั้นเราก็จะติดตั้ง package ด้านล่างนี้เข้าไปให้กับตัวเว็บของเรานั่นเอง

```
dotnet add package Microsoft.Azure.AppConfiguration.AspNetCore --version 3.0.0-preview-011100002-1192
```

สุดท้ายก็ไปที่ไฟล์ `Program.cs` เพื่อไปบอกให้มันไปอ่านค่าจาก App Configuration Service นั่นเอง (โค้ดของ dotnet core 2 กับ dotnet core 3 ไม่เหมือนกันนะดูดีๆ

{% tabs %}
{% tab title=".NET Core 2.x" %}

```csharp
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            var settings = config.Build();
            config
            .AddAzureAppConfiguration("AppConfigConnectionStrings");
        })
        .UseStartup<Startup>();
```

{% endtab %}

{% tab title=".NET Core 3.x" %}

```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
    {
        var settings = config.Build();
        config
        .AddAzureAppConfiguration("AppConfigConnectionStrings");
    })
    .UseStartup<Startup>());
```

{% endtab %}
{% endtabs %}

ซึ่งในโค้ดด้านบนเราจะเห็น **AppConfigConnectionStrings** ซึ่งตรงจุดนี้เราจะต้องเอา **`Connection String`** ของตัว App Configuration Service มาใส่ไว้ เพื่อให้ตัวเว็บของเราสามารถเข้าไปอ่านความลับต่างๆมาได้นั่นเอง โดยเราจะเข้าไปเอาค่านี้ได้จากเมนู **`Access keys`** ของเจ้า App Configuration Service นั่นเอง ตามรูปด้านล่างเลย แล้วกดปุ่ม Copy ที่ Connection string เอานะ

![](/files/-LpqXTaR1A_jy0_ciojZ)

หลังจากที่เอาที่ copy ไปวางใส่ละ สุดท้ายเราก็จะลองเปิดเว็บในเครื่องตัวเองดู ซึ่งผลลัพท์ก็คือ

![Localhost](/files/-M1lg2XR7CaU53u4MmAq)

ตัวเว็บที่อยู่ใน Localhost ของเรา มันจะไปใช้ Configuration ที่อยู่บน **App Configuration** แทนนั่นเองครับ ดังนั้นถัดไปผมก็จะลอง Deploy ตัวเว็บนี้ขึ้นไปลองบนคลาว์ แล้วลองเปิดดูบ้างนะ ซึ่งผลลัพท์ที่ได้ก็คือ

![Cloud](/files/-LrKLYmFbl1qECMHplgq)

ตัวเว็บที่ที่อยู่บนคลาว์ของเรา มันก็ไปใช้ Configuration ที่อยู่บน **App Configuration** เหมือนกับที่อยู่ใน Localhost นั่นเอง ซึ่งการใช้วิธีนี้มันจะช่วยให้เราไม่ต้องเก็บ Configuration ไว้บน Web App Service แล้วนั่นเอง เพียงแค่เราแยก Subscription ที่ทำการเก็บ App Configuration ออกจาก Web App Service เพียงเท่านี้จะทำให้ Developer ถูกจำกัดสิทธิ์ในการเข้าถึงได้แทบจะเป็นแบบที่เราอยากได้ละ

## 😡 อย่ามาหลอกกันนะเฟร้ย!!

จากที่ทำมาทั้งหมดเหมือนมันจะดูดี แต่ถ้าดูดีๆเราจะพบว่าเจ้า **`ความลับ`** มันกลับมาอยู่ในรูปแบบของ Hard Code ที่ฝังไว้กับ source code เหมือนบทความแรกเลย และ ต่อให้เราให้มันไปอ่าน Environment Variable หรืออะไรก็ตาม มันก็ไม่ได้เป็นการซ่อนความลับอะไรเลยนั่นเอง

คำตอบของผมคือ **ใช่ครับ** มันเป็นการย้อนวนกลับมาที่ปัญหาแรกๆของเรา แต่ผมถือว่า **มันเป็นการถอยกลับที่มีความหมาย** เพราะในบทความนี้เราได้เตรียม **infrastructure** เพื่อให้ระบบของเราทำการแยก ความลับ ออกจากคนที่ไม่ประสงค์ดีได้แล้ว ดังนั้นเดี๋ยวเราไปดูบทความที่ 4 ตัวถัดไปว่าเราจะจัดการเก็บซ่อนของพวกนี้ทุกเม็ดได้ยังไงกันบ้างดีกั่ว

## 🎯 สรุปคร่าวๆก่อนไปต่อ

ตอนนี้ปัญหาบางตัวถูกแก้ไป แต่ตัวเก่าบางตัวก็กลับมาทักทายเราเช่นเคยแล้วนะ ดังนั้นมาอัพเดทกันหน่อยดีกั่ว

* การผัง Secret ไว้เป็น Hard code ทำให้เราต้อง Build & Deploy โปรเจคใหม่เท่านั้น
* ใน Source code ของมี Secret ติดเข้าไปใน commit เสมอ
* Developer บางคนอาจจะรู้ Secret ซึ่งเขาอาจจะเป็นคนร้ายในอนาคต หรือ เป็นจุดที่อันตรายถ้าเขาเก็บมันไว้ไม่ดี
* ถ้ามีคนที่มี access เข้าถึง service บนคลาว์ตัวนั้นๆได้ เขาก็สามารถเข้ามาดู secret เหล่านั้นได้เหมือนเดิม
* ~~ถ้าเราไม่ให้ access เข้าถึง service ตัวนั้นๆ เราก็จะเอาแอพขึ้นคลาว์ไม่ได้~~


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.saladpuk.com/cloud/cloud-playground/app-config-03.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
