發表文章

禁止RDP(遠端桌面)用戶連上VM時複製、貼上或掛載本機硬碟

圖片
最近開課,為了讓學員有最好的上課體驗,我們都大手筆、大成本的為每位學員準備一台雲端虛擬機,當作上課環境。這樣學員就不需要自己安裝上課所需的軟體了,也不用弄亂自己原本的電腦環境,只要以遠端桌面連上即可。 不料近期,碰到某企業客戶的資安同仁認為,這虛擬機…不安全。 因為,同仁有可能在公司上課時把公司檔案偷偷複製到虛擬機,然後回家後,再下載到回家裡電腦!!! (呃…) 要求我們設法處理。 好唷,沒問題,就來處理處理~ 怎麼強制讓用戶連上虛擬機時,不能複製貼上也不能掛載本機硬碟呢? 其實,只需要開啟… 群組原則 --> 電腦設定 --> 系統管理範本 --> windows 元件 --> 遠端桌面服務 --> 遠端桌面工作階段主機 --> 裝置及資源重新導向 然後把剪貼簿和磁碟重新導向關閉即可,很容易吧。 後記: 我突然想到,我有一個在高收入產業上班的朋友(業務單位,非資訊人員),有次他因為電腦使用上的問題向我求救,我請他擷圖用賴傳給我,他說電腦沒法擷圖,我不解。搞了半天,他最後用手機拍了螢幕的照片傳給我,被我嫌怎麼歪歪斜斜解析度那麼差,他才說: 『不錯了,這還是偷拍的』。 他說:公司不能拍照,不能擷圖,不能下載檔案,不能OOXXOOXX。 我說:『哇,你們控管這麼嚴格啊!?』 他說:『你才知道? 公司基本上就把我們都當作是 “賊” 來看待。』 我大笑:『哈哈哈,很好、很好』 心想,這就是所謂的『零信任』吧😛。

使用CLI發送免費的LINE Notify通知

圖片
Overview 這個 Lab 介紹如何透過Command Line來免費發送的LINE Notify通知 Prerequisites 下載安裝 .net core sdk 3.1 以上版本 here 安裝 LINE CLI 工具1.0.19以上版本 here Steps 在command line輸入 dotnet --version,確定您的執行環境具備 .net core 3.x 以上版本 PS C:\ > dotnet --version 系統會出現類似底下畫面… PS C:\ > dotnet --version 5.0.202 2.接著執行底下指令, 安裝 LINE CLI 工具… PS C:\ > dotnet tool install --global line.cli 如果成功,系統會出現類似底下畫面… 工具 'line.cli' 已安裝。 申請 LINE Notify Token 前往 LINE Notify ,以個人帳號登入,至個人頁面的最下方『發行權杖』: 選擇訊息要發送到哪一個群組(亦可發送給自己一人): 按下『發行』後,可取得類似底下的 Notify Token: 如果是發送給群組,記得將 LINE Notify帳號加入該群組中。 未來,只需要透過底下Command Line指令,即可免費發送LINE訊息給特定群組: PS C:\ > line notify -n [ NotifyToken ] -m 要發送的訊息 你會發現訊息就會出現在LINE通知中: CLI本質上也是透過 LINE官方的Rest API來完成的: POST /api/notify HTTP/1.1 Host: notify-api.line.me Authorization: Bearer ___Notify_token___ Content-Length: 135 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-D...

Azure DevOps - 在Job之間傳遞變數值

圖片
學員來信問到了,如何在 Azure DevOps Pipeline 的多個 Job 之間,傳遞變數值。這有一些知識背景。 首先,Azure DevOps 的一條 Pipeline 中可以有多個Job,每個Job可以獨立運行,或是相依運行(例如Job A完成後再運行 Job B),每一個Job裡面才是多個Tasks(或是Steps),類似底下這樣: 假設,上面兩個 Job 之間有相依性,如何在第一個 Job 完成之後,把特定的資訊,傳遞到第二個 Job 之中呢? 一般來說我們會想到 Pipeline Variable。底下這樣的輸出,可以建立出一個 Pipeline Variable,基本的設計是在 tasks 之間傳遞資訊: - powershell : | Write-Host "##vso[task.setvariable variable=myVar;]foo" - bash : | echo "##vso[task.setvariable variable=myVar;]foo" 上面這樣的指令可以定義一個名稱為 myVar 的變數,然後設定其值為 foo。 要使用其值,就可以採用 $(變數名稱) 這樣的指令: - powershell : | Write-Host "變數值: $(myVar)" - bash : | echo "變數值: $(myVar)" 問題是,上述的變數預設狀況下只能在單一的job之間使用,如果要pass到另一個job,得做些設定。首先,變數設定得多加一個 isOutput=true,表明要在下一個job中使用: 接著,要在第二個Job中,設定一個環境變數(例如下圖的B1StagePara),來承接第一個output變數myPara1: 這樣在第二個job中才可以使用。ok, 確實有點迂迴。 不過如此一般,你就可以順利的把第一個job產出的資訊,pass給第二個job了: 整段 Yaml 檔案如下: trigger : - main pool : vmImage : ubuntu - latest stages : - stage ...

敏捷導入流程 - ADAPT

圖片
端午節前,上課的時候,又有學員說到: 『老師,你說的這些都很對,但在公司裡面,老闆(PM/主管)就是沒法接受我花額外的時間來做這些(單元測試、重構…etc.)。而且同仁也不覺得這些東西(測試左移、敏捷開發、頻繁交付…etc.)有那麼重要…』 相信我,敏捷轉型和DevOps導入做久了,我常常碰到這個事情。 上周五我才在 Agile Summit 2023 分享這張圖,幾十分鐘演講我無法把心裡的感受 100% 講清楚,但我得說,組織數位轉型,如果只是技能(Ability)的教導,是很難很難很難達到推動的效果的。 因為同仁(或老闆)根本不認為自己有改變的需要。 因此,在培養同仁的能力(Ability)之前,先得營造團隊對於改變的渴望(Desire),而這必須從讓同仁和團隊意識(Awareness)到自己需要改變開始。(上圖) 過去很多公司把教育訓練(Ability)當作Awareness來使,不是不行,只是成效很勉強。上週五分享時,我們同仁有說過,Awareness的建立,很像是持續的在靜止的湖面一直丟一顆一顆的小石子,讓漣漪可以一波一波的傳遞出去。為了達成這件事,同仁用了很多策略,包含在企業內定期舉辦內部社群聚會、持續帶狀的發送電子報、持續舉辦的分享會和教育訓練、安排技能陪跑指導…這些都只是開始,經過了不斷的努力,成果才會慢慢開始看到。 這還有一個前提,就是大老闆對數位轉型在觀念上是支持的,因此不會挑戰你為何要做這些、那些…。然後,我們才有機會在企業內,依照這個循環,把一種技術、或一種方法逐漸落地、紮根,然後開始改變同仁的習慣,最後才能實踐轉型。 否則要不了多久,你帶入的所有新做法,都會被組織的慣性所掩蓋,同仁會逐漸回到原本那個樣子,船過水無痕。 數位轉型,說起來感覺很容易,得做過才知道箇中難處在哪裡。 『如果老闆就是不支持呢?』學員問。 我說:『那你做你的,不要跟老闆說。』我特別補充:『這不是我說的,這是Martin Fowler說的。』(圖二) 記得,你的關注範圍不要大於你的影響範圍,否則,你自己會很痛苦。(屈原就是這樣) 如果你的影響範圍目前就只有你自己的團隊,那就從你的團隊安安靜靜地開始做起。如果你做的事情是對的,要不了多久,你的成果就會被大家看到,你的影響範圍就有機會逐漸擴大,這時你的關注範圍(在組織內可進行轉型的影響半徑),就可...

出一張嘴寫程式的時代真的會來嗎?

圖片
古時候,有個字叫做 人機介面 ,也就是人和機器溝通的通道。一直以來,人和機器的溝通是不直接的。 操作電腦,你得透過滑鼠、鍵盤、或觸控螢幕,而不是像你跟身邊其他人溝通時,可以透過對話和語言來進行。 這是一種阻礙,即便由來已久,即便你已經習慣,這仍是一種阻礙。 然而阻礙帶來了限制,但也帶來了機會。 所以開始有 程式設計師 這個行業,程式設計師把人們的需要,翻譯成電腦可以看得懂的程式碼,操控電腦來進行人們想實現的功能。自從電腦誕生以來,這個活兒就沒消失過。 上週,我去集英信誠和百敬老師聊天(其實是錄影),從ChatGPT談到哲學和宗教,中間有一個話題,我們談到了人機介面即將改變。在過去,開發人員必須得把輸入(input)變成結構化的資料,例如表單、欄位、這樣電腦才有機會能夠理解,從而進行處理和運算。 先不管ChatGPT輸出的正確性如何(如果你上完我們的課就知道,現階段根本不該期待一個 生成式AI 所產出的東西是正確的,它只是依照格式產生看起來像樣的內容,而非正確的內容,內容的正確性得靠你的加工),但這一波ChatGPT會造成轟動的潛在原因是, 它似乎聽得懂你說的話,而這才是重點 。 Chat Bot幾年前早過炒過一波了,結果如何? 成功了嗎? 別問我,你自己說說你對現在哪一家銀行的AI助理或是聊天機器人滿意的? 幾乎沒有。而過去Siri能夠回應你的,也總是那麼幾個簡單的指令,複雜一點的對談,整個就不行了。 但這一波ChatGPT帶來的第一個驚訝,是你發現,它似乎還真聽得懂你說的話。 沒錯,ChatGPT從去年11月底問世到今天才半年,你跟它的溝通大致上不會讓你失望,對吧? 也就是說,ChatGPT對於自然語言的理解(NLU),好過市面上可以見到的大部分ChatBot。它能夠清楚地抓到你的intent和entities,並且對前後文的理解有很高的掌握度。 這也是我上周六在彰化小聚的時候,分享的重點之一。 ChatGPT對於ChatBot最大的價值是,這是有史以來第一次,NLU開始讓社會大眾滿意(相當高比例的可以接受),並且API成本還算是負擔的起。 ChatBot開發人員,終於有機會突破過去的制約,讓你的ChatBot有機會真的理解用戶在說些什麼(至少讓用戶這樣覺得),而且是透過自然語言,不用再去管傳統的表單輸入或結構化資料輸入了,這是人機介...

微服務(或API)的用戶身分驗證

圖片
最近不只一次被問到這個問題。 在應用程式(或前端展示層App)呼叫API(或微服務)的時候, 雖然都會有攜帶API KEY來驗證呼叫者(App)的身分,但若是要知道用戶的身分(就是誰操作這個App來呼叫API的?),又該怎麼辦呢? 一般來說,當我們討論微服務開發時,大多不一定會包含UI(套句Uncle Bob說的,UI是細節)。因此,在實作用戶端(End-User)的身分驗證時,往往只會做到UI(展示層)為止。但實務上,不管是多層式架構或是微服務架構,UI(展示層)又會需要呼叫微服務(或應用層API)來實現系統功能。 像是底下這樣: 但在UI呼叫微服務(應用層API)時,被呼叫端需要確認呼叫端(UI/展示層)具有呼叫微服務(或API)的權限,這一段,大多只會採用API KEY來驗證。 例如: POST / APIName HTTP / 1.1 Host : domain . com Content - Type : application / json ApiKey : 3126616e - c14b - 4ba8 -8617 - d7349541ce40 Content - Length : 23 { "data" : "infomation" } 然而,若某些微服務(或API)運作時還需要得知用戶端身分,又會怎麼做呢? 簡單一點的作法,是直接透過JSON Body告知API當前用戶是誰(前提當然是API信任這個呼叫端),這樣既暴力又簡單,如果想更嚴謹一點,可以在Header攜帶先前用戶已經驗證過的Access Token/JWT Token來實現: User Web App (UI) Microservices(API) 登入(Cookies/JWT/OAuth) 登入成功(保留User Token) ...若不須用戶身分資訊... 發送請求 呼叫API (帶上API Key) (API確認呼叫者是哪個App)返回結果 顯示結果 ...當需要用戶身分資訊... 發送請求(帶上User Token) 呼叫API (帶上API Key, User Token) (API確認呼叫者是哪個App, 哪位User)返回結果 顯示結果 User Web App (UI) Microservice...

單體式系統與微服務

圖片
最近重讀 Sam Newman的『建構微服務』,覺得實在精彩。真心以為,想作微服務系統的開發人員,都值得花點時間讀一下第一章,絕對值回票價。 我把讀完的感想和摘要寫在下面,希望能夠幫助大家釐清什麼是微服務(以及什麼不是)。 傳統來說,古典的單體式應用(Monolith)大多意指在同一個行程內運行的應用系統,底下是典型的單體式應用程式與其變形。 古典的單體應用程式 一個應用程式,後面搭配一套DB,但上面這樣的系統已經愈來愈少了,只剩下像是手機app或是極端傳統的desktop app。 如今大部分的單體式應用系統(不管是desktop或web),大多會是底下這樣: 模組化單體式應用程式 模組採用同樣(或近乎類似)的開發技術。 模組間有共用的基礎設施(infrastructure),像是log, security…etc. 即便模組可以獨立運行,但依舊必須一起佈署。 單體式應用系統的優點 相較於微服務,單體式應用系統其實有很多優點: 簡化開發人員工作流程 簡化監控、故障排除、與測試 這是事實,但Sam Newman強調『最近人們開始將單體式系統視為「時代遺產」的同義詞,仿佛這種系統有著什麼本質上的問題,是一個需要避免的東西…』 但其實,單體式架構只是一種選擇,甚至是一種有效的選擇。Sam Newman認為:『這是一個作為架構風格合理的 預設選項(我欣賞這句話) 』,換句話說,我也認為,面對架構選擇,人們應該尋找一個能被說服使用微服務的理由… 微服務架構 我們很久以前就談過微服務,但到底什麼是微服務? Sam Newman在書中,對微服務的核心概念做了說明,我覺得包含幾個重點: 可獨立佈署:微服務的每一個單元應該能夠單獨部署,而不需要依賴其他服務。這種可抽換性使得應用程式更加靈活,可以更快地部署和更容易地維護。這也意味著, 當你抽換一個微服務、另一個微服務不該受到影響。 圍繞著Business Domain塑模: 每個微服務都應該圍繞一個具體的Business Domain來設計,而不是根據技術或企業組織架構來劃分 。這種業務驅動的作法使得應用程序更加緊密地與業務相關,並能夠更好地支撐業務需求的變化。(這一點很多公司其實先天就無法做到,參考底下『架構和組織的調整』) 大小:微服務應該要足夠小,以便能夠單獨佈署和管理...

找回被遺忘了的目標

圖片
跟以前同事吃飯… 這位朋友在幾年內,從公司的副理升到副總,最近買了新車,讓人挺羨慕的。 本來吃飯只是閒聊技術問題,席間不知道為何,談到目標設定。這主題我在上敏捷課程時,多多少少也有涉獵,看他這幾年事業突飛猛進,我不禁好奇地問,他對目標設定的看法,我心想 : 會不會還有什麼我還不知道的秘訣? 朋友說:『首先,目標設定要明確。』我心裡想,這個自然,這我很清楚。 因此我說:『要有時間、有數量、我上課時也這麼跟學員說。』 『對,就像你若是跟上帝禱告要有錢,但什麼叫做有錢呢? 每個人都有錢啊,一塊錢也是錢。你要很清楚地寫下來,你要多少錢?』他說。 我心想:『恩,有時間,有數量、雖然感覺很容易,但這一關其實很多人已經做不到了。白紙黑字寫下來,確實是有力量的。也能夠幫助自己認真面對和思考。』 他接著說:『不管是個人還是我的團隊,我都是這樣做的。一般來說,一定會有一個數字,例如今年要賺多少錢,存多少錢之類的。』『幾年前我換工作時也是,希望不要距離太遠…那多遠? 幾公里,我就寫下來,然後開始找這個距離以內的所有公司…』我聽得嘖嘖稱奇。 我繼續追問: 『就這樣? 還有其他秘訣嗎?』 『沒有啦,只剩…』他語帶保留的讓我好奇,我立刻追問『甚麼秘訣?』 朋友說 : 『寫下來具體目標之後,每天早上起來就看著大聲唸。』 『啊?』我有點不相信:『真的嗎?你每天都有唸?』 他有點不好意思的說:『呵,也不是每天啦,但…一年365天大概也有300天吧。』這回換我訝異了,其實即便只是300天,也很不可思議。 他說,大部分人即便訂了一個清晰的目標,結果卻還是沒做到。常常因為他們都『忙到忘了』。我們每天生活中有太多太多的雜事,和『看起來重要』的緊急事項,如果你沒有每天唸一次自己當初訂下的目標,常常很容易忘記哪些才是你真正重要的。 這個做法其實很簡單,我也跟很多人分享過,然而大部分人都不會真的去做。但是我覺得,它對我幫助很大… 『每天唸?』…這倒是我之前沒有做到的事情。 我心裡開始想…明確可量測的目標、有時間、有數量,這些我早就有做到,沒問題…但確實,我還是常常因為其他看起來更重要的緊急工作,打亂了一周甚至一個月的規劃。讓自己忘了已經訂好的目標,在努力的事情上走偏了。讓自己忙的焦頭爛額,卻把時間花在當下看起來重要,但對整體目標不痛不癢的事情上… 每天唸,其實就是校正羅盤的方向...

在 .net core 中實現AOP

圖片
AOP(Aspect-Oriented Programming,剖面導向程式設計)是一種軟體開發方法論,其主要目的是將商業邏輯(Business Logic)和橫切關注點(Cross-Cutting Concern, 例如 Logging, Permission , Exception Handling…etc.)分離出來,進而使系統更加職責清晰、易於維護和擴展。 在AOP中,橫切關注點被稱為切面(Aspect),切面是一種跨越多個物件和方法的模塊化程式碼,用來實現特定的橫切關注點。在AOP中,我們可以將切面應用(Apply)到一個或多個類或方法上,從而實現這些類或方法的橫切關注點。 AOP的主要概念是,若能將橫切關注點從主要商業邏輯(Business Logic)中分離出來,即可達到降低耦合、提高軟體重用性的效果。 舉例說明 首先來整理一下這個命題,我們知道AOP想把Business Logic和Infrastructure Logic做一個切割,達成cross-cutting concerns的獨立性,但這樣講很抽象,具體情境是什麼呢? 看底下這一段code: using System ; namespace testAOP { class Program { static void Main ( string [ ] args ) { //建立BMIProcessor物件 BMIProcessor BMI = new BMIProcessor ( ) ; BMI . Height = 170 ; BMI . Weight = 70 ; //計算BMI var ret = BMI . Calculate ( ) ; //顯示 Console . WriteLine ( $ "BMI : {ret}" ) ; Console . WriteLine ( "Press any key for continui...

使用IoC與DI有何意義? (五) 透過設定實現注入

圖片
這一篇文章,照說應該接在之前寫過的 這篇 之後。但沒想到是,上一篇已經是 2020年的事情! 這連載也間隔太久了,哈。 在理解了DI的原理,並且知道注入的做法之後,我們繼續往下看,如果要動態實踐注入,該如何進行? 先前我們看到的程式碼中的注入,都是修改 program.cs 中的 AddTransient 來進行的,例如: serviceCollection . AddTransient < ISalaryFormula , SalaryFormula > ( ) ; 但如果我們想對 ISalaryFormula 這個介面,動態注入實作的類別,但不想改程式碼,可以怎麼做呢? 沒什麼複雜的,就是使用設定檔 appSettings.json,例如,我們可以建立這樣的配置: { "MyServiceConfig": { "MyServiceType": "consoleDI.SalaryFormula" } } 其中以字串描述了一個類別的路徑(NameSpace.ClassName),例如: “consoleDI.SalaryFormula” 如果要額外描述在哪一個組件(.dll)內,路徑則是 “NameSpace.ClassName, DllName” 有了設定之後,我們在主程式中,加入讀取該設定的程式碼(底下7-12行): public class Program { //這裡才是真正的進入點 main static void Main ( string [ ] args ) { //讀取appsettings.json中的設定,決定用哪一個類別實作 IConfiguration config = new ConfigurationBuilder ( ) . SetBasePath ( Directory . GetCurrentDirectory ( ) ) . AddJsonFile ( "appsettings.json" , optional : false ) ...